5 个JavaScript Util 函数为你的应用程序增添趣味

web前端开发

共 4303字,需浏览 9分钟

 ·

2021-09-14 11:25

英文 | https://betterprogramming.pub/5-javascript-promises-util-functions-to-spice-up-your-apps-665affca236c

翻译 | 小爱


1、 模拟延迟

有时我们需要模拟某些动作之间的特定延迟。使用以下代码就很容易实现:

function delay(timeout) {   return new Promise(        (resolve) => {            const timeoutHandle =                 setTimeout(() => {                    clearTimeout(timeoutHandle);                    resolve()                                 }, timeout);   });}

这个util函数的用法如下:

async function(){   console.log('The first log');   await delay(1000);   console.log('The second log with 1000 ms delay')}

作为输出,我们将立即看到第一个日志,第二个日志在 1000 毫秒后出现。

2、分解长期运行的任务

由于 JS 是一种单线程语言,我们可能会遇到 UI 延迟或无响应的服务器来处理新的即将到来的请求。它通常发生在应用程序试图处理长时间运行的任务时。

有时,需要一个工具完成将长时间运行的任务进行拆分为多个块,以便有机会完成另一个应用程序代码。这是代码:

function nextFrame() {     const nextTick = requestAnimationFrame || setImmediate.      return new Promise((res) => nextTick(() => res()))}

这个util函数的用法:

async longRunningTask(){   let step = 0;   while(true){        if (++step % 5 === 0){             await nextFrame();        }   }}longRunningTask();console.log('The first log')

尽管我们运行了一个无限循环,但这个函数的第 5 步为处理其他应用程序的代码开辟了道路。

3、为 Promise 添加超时限制

如果某些操作正在使用 Promise 处理,那么使用以下代码很容易为其添加超时限制:

function addTimeoutToPromise(targetPromise, timeout) {   let timeoutHandle;   const timeoutLimitPromise = new Promise((res, rej) => {       timeoutHandle = setTimeout(           () => rej(new Error('Timeout exceeded')),           timeout       );   });   return Promise.race([targetPromise, timeoutLimitPromise])       .then((res) => {           clearTimeout(timeoutHandle);           return res;       });}

这个util函数的用法如下图所示:

addTimeoutToPromise(     delay(1000).then(() => console.log('Completed')), 2000);// --> CompletedaddTimeoutToPromise(    delay(2000), 1000).catch((e) => console.error(e.message))// --> Timeout exceeded

4、按顺序完成 Promise

假设我们有一个 API,它对可以同时完成的请求数量有限制。它迫使我们开发一种方法,允许一个接一个地完成一堆承诺。

首先,与 Promise.all 不同,我们不能只将一个 promise 数组传递给我们的方法,因为一旦创建了 promise,所有这些都会立即完成。

因此,我们的 util 函数应该获得一组函数,这些函数可以按需创建承诺,我们可以控制这个承诺何时开始竞争,如下所示:

function completeInSequence(promiseFactories: () => Promise<any>){    ...}

从字面上看,我们需要构建以下结构,它允许按顺序完成承诺。下面是一些代码来做到这一点:

Promise.resolve()   .then(() => promiseFacrories[0]()   .then(() => promiseFactories[1]())   ...   .then(() => promiseFactories[N]())

在这里, Promise.resolve 和 Array.reduce 发挥作用。Promise.resolve 通常用作构建承诺链的起点。这是帮助解决此问题的代码:

function completeInSequence(promiseFactories: () => Promise<any>) {   return promiseFactories.reduce(      (chain, promiseFactory) => chain.then(()=> promiseFactory()),      Promise.resolve()   );}

很简单的实现。让我们用以下内容测试它:

completeInSequence([   () => delay(1000).then(() => console.log('1')),   () => delay(1000).then(() => console.log('2')),   () => delay(1000).then(() => console.log('3'))])

你将看到所有日志消息之间的间隔为 1000 毫秒。

5、只同时完成 N 个 Promise

我们考虑到使用 API 的带宽是很酷的,但我认为它可能允许我们同时完成多个请求。

好吧,和前面的例子一样,我们仍然需要一个创建 promise 的函数,它提供了控制 promise 何时完成的机会。第二个变量是池的最大大小,它反映了可以同时处理的承诺数量。下面是一个例子:

function completePromisesInPool(    promiseFactories: () => Promise<any>,    maxPoolSize: number) { .... }

首先,函数应该在我们需要开始完成N个promise的地方返回Promise。

之后,只要任何一个运行承诺完成,就意味着我们在池中有一个空闲插槽,如果它仍然存在,另一个承诺可能会取代这个位置,否则解决包装承诺。这是执行此操作的函数:

function completePromisesInPool(    promiseFactories: () => Promise<any>,    maxPoolSize: number) {   return new Promise((res) => {      let nextPromise = 0;      const runPromise = () => {         nextPromise++;         if (nextPromise > promiseFactories.length) {            res();            return;         }         return promiseFactories[nextPromise-1]()              .then(() => runPromise())      }
Array.from({length: maxPoolSize}) .map(() => runPromise()); })}

让我们使用以下内容对其进行测试:

completePromisesInPool([   () => delay(1000).then(() => console.log('1')),   () => delay(1000).then(() => console.log('2')),   () => delay(1000).then(() => console.log('3')),   () => delay(1000).then(() => console.log('4')),   () => delay(1000).then(() => console.log('5')),   () => delay(1000).then(() => console.log('6'))  ], 2)

你将看到 console.log 以 1000 毫秒的间隔分批打印两条消息。这是它的样子:

就是这个样子。

感谢你的阅读。

学习更多技能

请点击下方公众号

浏览 3
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报