5 個JavaScript Util 函數(shù)為你的應(yīng)用程序增添趣味

英文 | https://betterprogramming.pub/5-javascript-promises-util-functions-to-spice-up-your-apps-665affca236c
翻譯 | 小愛
1、 模擬延遲
有時我們需要模擬某些動作之間的特定延遲。使用以下代碼就很容易實現(xiàn):
function delay(timeout) {return new Promise((resolve) => {const timeoutHandle =setTimeout(() => {clearTimeout(timeoutHandle);resolve()}, timeout);});}
這個util函數(shù)的用法如下:
async function(){console.log('The first log');await delay(1000);console.log('The second log with 1000 ms delay')}
作為輸出,我們將立即看到第一個日志,第二個日志在 1000 毫秒后出現(xiàn)。
2、分解長期運行的任務(wù)
由于 JS 是一種單線程語言,我們可能會遇到 UI 延遲或無響應(yīng)的服務(wù)器來處理新的即將到來的請求。它通常發(fā)生在應(yīng)用程序試圖處理長時間運行的任務(wù)時。
有時,需要一個工具完成將長時間運行的任務(wù)進行拆分為多個塊,以便有機會完成另一個應(yīng)用程序代碼。這是代碼:
function nextFrame() {const nextTick = requestAnimationFrame || setImmediate.return new Promise((res) => nextTick(() => res()))}
這個util函數(shù)的用法:
async longRunningTask(){let step = 0;while(true){if (++step % 5 === 0){await nextFrame();}}}longRunningTask();console.log('The first log')
盡管我們運行了一個無限循環(huán),但這個函數(shù)的第 5 步為處理其他應(yīng)用程序的代碼開辟了道路。
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函數(shù)的用法如下圖所示:
addTimeoutToPromise(delay(1000).then(() => console.log('Completed')), 2000);// --> CompletedaddTimeoutToPromise(delay(2000), 1000).catch((e) => console.error(e.message))// --> Timeout exceeded
4、按順序完成 Promise
假設(shè)我們有一個 API,它對可以同時完成的請求數(shù)量有限制。它迫使我們開發(fā)一種方法,允許一個接一個地完成一堆承諾。
首先,與 Promise.all 不同,我們不能只將一個 promise 數(shù)組傳遞給我們的方法,因為一旦創(chuàng)建了 promise,所有這些都會立即完成。
因此,我們的 util 函數(shù)應(yīng)該獲得一組函數(shù),這些函數(shù)可以按需創(chuàng)建承諾,我們可以控制這個承諾何時開始競爭,如下所示:
function completeInSequence(promiseFactories: () => Promise<any>){...}
從字面上看,我們需要構(gòu)建以下結(jié)構(gòu),它允許按順序完成承諾。下面是一些代碼來做到這一點:
Promise.resolve().then(() => promiseFacrories[0]().then(() => promiseFactories[1]())....then(() => promiseFactories[N]())
在這里, Promise.resolve 和 Array.reduce 發(fā)揮作用。Promise.resolve 通常用作構(gòu)建承諾鏈的起點。這是幫助解決此問題的代碼:
function completeInSequence(promiseFactories: () => Promise<any>) {return promiseFactories.reduce((chain, promiseFactory) => chain.then(()=> promiseFactory()),Promise.resolve());}
很簡單的實現(xiàn)。讓我們用以下內(nèi)容測試它:
completeInSequence([() => delay(1000).then(() => console.log('1')),() => delay(1000).then(() => console.log('2')),() => delay(1000).then(() => console.log('3'))])
你將看到所有日志消息之間的間隔為 1000 毫秒。
5、只同時完成 N 個 Promise
我們考慮到使用 API 的帶寬是很酷的,但我認為它可能允許我們同時完成多個請求。
好吧,和前面的例子一樣,我們?nèi)匀恍枰粋€創(chuàng)建 promise 的函數(shù),它提供了控制 promise 何時完成的機會。第二個變量是池的最大大小,它反映了可以同時處理的承諾數(shù)量。下面是一個例子:
function completePromisesInPool(promiseFactories: () => Promise<any>,maxPoolSize: number) { .... }
首先,函數(shù)應(yīng)該在我們需要開始完成N個promise的地方返回Promise。
之后,只要任何一個運行承諾完成,就意味著我們在池中有一個空閑插槽,如果它仍然存在,另一個承諾可能會取代這個位置,否則解決包裝承諾。這是執(zhí)行此操作的函數(shù):
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());})}
讓我們使用以下內(nèi)容對其進行測試:
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 毫秒的間隔分批打印兩條消息。這是它的樣子:

就是這個樣子。
感謝你的閱讀。
學(xué)習(xí)更多技能
請點擊下方公眾號
![]()

