同事为难我:如何巧妙应对Promise的应用难题?
背景
背景是这样的,前同事给我出了一个难题,原因是他在最近找工作面试中被问到关于 Promise
相关的问题,单独我们看问题,我们其实每个任务都可以简单地做出来,但是需要组合考虑整体的步骤,和实际问题考我们的核心内容是什么?我很困惑顺便复习一下对 Promise
的理解
问题
实现一个简易的序列操作,支持sleep, log, exec 三类操作 sleep:支持等待ms秒之后再执行下一个操作, log:支持同步打印一些信息, exec:支持传一个函数,函数都是异步(即返回一个Promise),当异步函数执行完成之后,才能继续下一个 用 js 实现。
拆分问题
要实现一个支持 sleep
、log
和 exec
三类操作的序列操作系统,可以创建一个操作队列,并依次执行队列中的操作。以下是一个基于 JavaScript 的实现:
想到操作队列自然是数组,里面管理多个 Promise
对象
Sleep
顾名思义,我们是将接收到一个参数,然后往执行某件事。参数是 ms 一般我们用毫秒做时间的单位,为了在setTimeout
这类方法中使用的时候,是单位一致的,那么我可以构思代码
function sleep(ms) {
queue.push(() => new Promise(resolve => setTimeout(resolve, ms)));
}
sleep(ms)
方法接受一个毫秒数ms
,返回一个新的Promise
,该 Promise 在ms
毫秒后解决。- 使用
setTimeout
实现等待功能。
log
打印方法,其实很简单,我只需要接收,一个需要打印的参数,message
。然后输出就好了,最后返回一个已经解决的 Promise
,我们需要有一个 Promise
队列概念
function log(message) {
queue.push(() => {
console.log(message);
return Promise.resolve(); // 返回一个已经解决的Promise
});
}
log(message)
方法接受一个字符串message
,在控制台输出该信息。- 返回一个已经解决的
Promise
。
exec
接收一个异步函数作为参数,然后放到队列当中
function exec(asyncFunc) {
queue.push(async () => {
await asyncFunc();
});
}
}
exec(asyncFunc)
方法接受一个返回Promise
的异步函数asyncFunc
,将其添加到队列中。
依次执行队列中全部的任务
function run() {
for (const task of queue) {
await task();
}
}
run()
方法异步地按顺序执行队列中的每个任务。- 使用
for...of
循环和await
保证任务按顺序执行。
我们需要整理一下代码,将全部的方法都返回 this
, 方便可以使用链式调用, 最后我们加上示例就完成了
最后结果
class Sequence {
constructor() {
this.queue = [];
this.currentPromise = Promise.resolve();
}
sleep(ms) {
this.queue.push(() => new Promise(resolve => setTimeout(resolve, ms)));
return this;
}
log(message) {
this.queue.push(() => {
console.log(message);
return Promise.resolve();
});
return this;
}
exec(asyncFunc) {
this.queue.push(async () => {
await asyncFunc();
});
return this;
}
async run() {
for (const task of this.queue) {
await task();
}
}
}
// 示例使用
const sequence = new Sequence();
sequence
.sleep(1000) // 等待 1 秒
.log("This is a log message.") // 打印日志
.exec(() => new Promise(resolve => {
setTimeout(() => {
console.log("Async function executed after 2 seconds.");
resolve();
}, 2000);
})) // 执行异步函数
.log("Sequence completed.") // 打印日志
.run(); // 运行队列
总结内容
Sequence
类:这是一个用于管理操作队列的类。它包含一个队列(this.queue
)来存储所有操作,以及一个currentPromise
用于跟踪当前的 Promise 链。sleep(ms)
方法:将一个返回 Promise 的函数推入队列,该函数在等待指定的毫秒数后解析。log(message)
方法:将一个同步日志操作推入队列,并返回一个立即解析的 Promise。exec(asyncFunc)
方法:将一个异步函数推入队列,该函数返回一个 Promise,确保在函数完成后才继续下一个操作。run()
方法:遍历队列中的所有操作,并确保它们按顺序执行。每个操作会等待前一个操作完成(通过await
)后再开始执行。
最后祝大家周末愉快,有一个美好的周末时光!!
转载自:https://juejin.cn/post/7372396200861646898