5 个JavaScript Util 函数为你的应用程序增添趣味
共 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
);
// --> 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 毫秒的间隔分批打印两条消息。这是它的样子:
就是这个样子。
感谢你的阅读。
学习更多技能
请点击下方公众号