在前端开发中,Promise 是异步编程的核心工具之一。了解其内部机制对于深入掌握 JavaScript 异步处理至关重要。在上节课中,我们学习了如何将执行函数放入队列。本节课,我们将探讨如何从队列中取出执行函数进行执行,以及如何管理这些执行函数。
执行函数的时机
执行函数的时机主要有两个:
- then 方法调用时:每次调用 then 方法时,都会将新的执行函数添加到队列中,并立即尝试执行队列中的函数。
- 状态改变时:当 Promise 的状态从 pending 变为 fulfilled 或 rejected 时,也需要执行队列中的函数。
执行函数后的处理
为了避免重复执行,执行函数后需要从队列中删除该函数。
删除任务队列的方式
- 先进先出:每次都取出队列中的第一个任务执行,然后删除。
- 避免循环删除:在执行过程中循环删除可能会导致遗漏或重复执行。
代码实现
class MyPromise {
// 省略其他部分...
/**
* 根据实际情况,执行队列
*/
_runHandlers() {
if (this._state === PENDING) {
// 目前任务仍在挂起
return;
}
while (this._handlers[0]) {
const handler = this._handlers[0];
this._runOneHandler(handler);
this._handlers.shift();
}
}
_runOneHandler(handler) {
// 根据handler的类型(onFulfilled或onRejected)执行相应的逻辑
// 这里需要异步执行,可以使用setTimeout
setTimeout(() => {
const result = handler.action(handler.value);
if (result instanceof MyPromise) {
result.then((res) => this._resolve(res), (err) => this._reject(err));
} else {
this._resolve(result);
}
}, 0);
}
/**
* Promise A+规范的then
* @param {Function} onFulfilled
* @param {Function} onRejected
*/
then(onFulfilled, onRejected) {
return new MyPromise((resolve, reject) => {
this._pushHandler(onFulfilled, FULFILLED, resolve, reject);
this._pushHandler(onRejected, REJECTED, resolve, reject);
this._runHandlers(); // 执行队列
});
}
/**
* 更改任务状态
* @param {String} newState 新状态
* @param {any} value 相关数据
*/
_changeState(newState, value) {
if (this._state !== PENDING) {
// 目前状态已经更改
return;
}
// 下面这个判断是为了处理value为Promise的情况
// 这一段代码课程中没有涉及,特此注释说明
if (isPromise(value)) {
value.then(this._resolve.bind(this), this._reject.bind(this));
return;
}
this._state = newState;
this._value = value;
this._runHandlers(); // 状态变化,执行队列
}
}
总结
通过深入理解 Promise 的内部机制,我们可以更好地控制异步任务的执行流程。本节课我们学习了如何从队列中取出执行函数进行执行,并在执行后从队列中删除,以避免重复执行。这对于编写高效、可靠的异步代码至关重要。