天天看点

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

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

英文 | 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
);
// --> Completed
addTimeoutToPromise(
    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 毫秒的间隔分批打印两条消息。这是它的样子:

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

就是这个样子。

感谢你的阅读。

学习更多技能

请点击下方公众号

继续阅读