天天看點

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 函數為你的應用程式增添趣味

就是這個樣子。

感謝你的閱讀。

學習更多技能

請點選下方公衆号

繼續閱讀