Promise/A+规范: 手写一个Promise polyfill
2023-09-21 17:22:50
深入理解 Promise:一步步构建自己的 Polyfill
Promise 的魅力
在现代 JavaScript 编程中,Promise 凭借其简化异步编程、提升代码可读性的优势,已成为不可或缺的工具。然而,在 ES6 之前,JavaScript 并没有原生的 Promise 实现。本文将带你亲手构建一个符合 Promises/A+ 规范的 Promise polyfill,让你从底层领会 Promise 的运作原理。
构建 Promise
1. 常量与工具方法
首先,定义一些常量和工具方法:
PENDING
、FULFILLED
和REJECTED
:表示 Promise 的三种状态。isFunction
和isObject
:判断函数和对象的工具方法。
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
function isFunction(fn) {
return typeof fn === 'function';
}
function isObject(obj) {
return typeof obj === 'object' && obj !== null;
}
2. Promise 构造函数
Promise 构造函数接受一个执行器函数作为参数,通过其提供的 resolve
和 reject
函数改变 Promise 的状态。
class Promise {
constructor(executor) {
this.state = PENDING;
this.value = undefined;
this.reason = undefined;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
const resolve = (value) => {
if (this.state !== PENDING) return;
this.state = FULFILLED;
this.value = value;
this.onFulfilledCallbacks.forEach((callback) => callback(value));
};
const reject = (reason) => {
if (this.state !== PENDING) return;
this.state = REJECTED;
this.reason = reason;
this.onRejectedCallbacks.forEach((callback) => callback(reason));
};
try {
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
}
3. Promise 的决议逻辑
3.1 成功决议
then(onFulfilled, onRejected) {
const promise2 = new Promise((resolve, reject) => {
if (this.state === FULFILLED) {
// 当 Promise 已经决议为成功,立即执行 onFulfilled
queueMicrotask(() => {
try {
const x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
});
} else if (this.state === PENDING) {
// 当 Promise 还在等待决议,将 onFulfilled 和 onRejected 回调函数存储起来,等待决议后再执行
this.onFulfilledCallbacks.push(() => {
queueMicrotask(() => {
try {
const x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
});
});
}
});
return promise2;
}
3.2 失败决议
catch(onRejected) {
return this.then(null, onRejected);
}
4. Promise.resolve() 和 Promise.reject()
static resolve(value) {
if (value instanceof Promise) {
return value;
}
return new Promise((resolve) => {
resolve(value);
});
}
static reject(reason) {
return new Promise((resolve, reject) => {
reject(reason);
});
}
5. Promise.all() 和 Promise.race()
static all(promises) {
return new Promise((resolve, reject) => {
const results = [];
let pendingCount = promises.length;
promises.forEach((promise, index) => {
promise.then(
(value) => {
results[index] = value;
pendingCount--;
if (pendingCount === 0) {
resolve(results);
}
},
(reason) => {
reject(reason);
}
);
});
});
}
static race(promises) {
return new Promise((resolve, reject) => {
promises.forEach((promise) => {
promise.then(
(value) => {
resolve(value);
},
(reason) => {
reject(reason);
}
);
});
});
}
结语
恭喜你完成了 Promise polyfill 的构建!通过这个过程,你不仅对 Promise 的内部运作有了更深入的理解,还掌握了编写可靠异步代码的技巧。
常见问题解答
-
Promise 有什么优点?
Promise 简化了异步编程,提升了代码的可读性和可维护性。 -
为什么我们需要 Promise polyfill?
ES6 之前的 JavaScript 没有原生 Promise 实现,polyfill 弥补了这一空白。 -
如何使用 Promise?
使用new Promise
创建一个 Promise 实例,并使用then
、catch
等方法处理其决议。 -
Promise.all() 和 Promise.race() 有什么区别?
Promise.all()
等待所有 Promise 决议完成,Promise.race()
等待第一个 Promise 决议完成。 -
如何测试 Promise polyfill 是否有效?
使用 promises-aplus-tests 等测试套件验证 polyfill 是否符合 Promises/A+ 规范。