手写Promise,跑Promise A+规范
2023-09-07 05:20:09
前言
在异步编程中,Promise是一种非常有用的工具,它可以帮助我们处理异步操作,并使代码更加简洁和可读。Promise A+规范定义了Promise对象的行为和用法,它被广泛地应用于JavaScript社区,并成为了JavaScript异步编程的标准。
Promise的基本概念
Promise是一个对象,它表示一个异步操作的最终完成或失败的状态。Promise有三种状态:pending、fulfilled和rejected。
- pending :表示异步操作尚未完成。
- fulfilled :表示异步操作已成功完成。
- rejected :表示异步操作已失败。
Promise对象可以通过then方法来注册回调函数,当Promise的状态发生改变时,相应的回调函数就会被调用。then方法有两个参数:onFulfilled和onRejected。onFulfilled在Promise的状态变为fulfilled时被调用,onRejected在Promise的状态变为rejected时被调用。
手写Promise
现在,我们来一步一步地手写一个Promise。
function Promise(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(this.value);
});
};
const reject = (reason) => {
if (this.state !== 'pending') {
return;
}
this.state = 'rejected';
this.reason = reason;
this.onRejectedCallbacks.forEach((callback) => {
callback(this.reason);
});
};
executor(resolve, reject);
}
在上面的代码中,我们定义了一个Promise类,并在构造函数中初始化了Promise的状态、值和原因,以及fulfilled和rejected回调函数的数组。然后,我们定义了resolve和reject方法,它们分别用于将Promise的状态改为fulfilled和rejected。
接下来,我们在Promise类中定义了then方法。
Promise.prototype.then = function (onFulfilled, onRejected) {
if (typeof onFulfilled !== 'function') {
onFulfilled = (value) => value;
}
if (typeof onRejected !== 'function') {
onRejected = (reason) => {
throw reason;
};
}
const promise2 = new Promise((resolve, reject) => {
if (this.state === 'fulfilled') {
setTimeout(() => {
try {
const x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (err) {
reject(err);
}
}, 0);
} else if (this.state === 'rejected') {
setTimeout(() => {
try {
const x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (err) {
reject(err);
}
}, 0);
} else {
this.onFulfilledCallbacks.push(() => {
setTimeout(() => {
try {
const x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (err) {
reject(err);
}
}, 0);
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
const x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (err) {
reject(err);
}
}, 0);
});
}
});
return promise2;
};
在上面的代码中,我们首先检查onFulfilled和onRejected是否为函数,如果不是,则将其替换为默认的函数。然后,我们创建一个新的Promise对象promise2,并在其构造函数中定义了resolve和reject方法。
如果当前Promise的状态是fulfilled,则我们使用setTimeout方法将onFulfilled回调函数推迟到下一个事件循环中执行。这确保了onFulfilled回调函数是在resolvePromise方法之后执行的,以防止出现同步错误。
如果当前Promise的状态是rejected,则我们使用setTimeout方法将onRejected回调函数推迟到下一个事件循环中执行。这确保了onRejected回调函数是在rejectPromise方法之后执行的,以防止出现同步错误。
如果当前Promise的状态是pending,则我们将onFulfilled和onRejected回调函数推入相应的数组中。当当前Promise的状态改变时,我们会调用这些回调函数。
最后,我们将promise2返回,以便可以将then方法链式调用。
测试Promise
现在,我们已经手写了一个Promise,我们可以使用单元测试来验证它的实现是否符合Promise A+规范。
const assert = require('assert');
describe('Promise', function () {
it('should be a function', function () {
assert.strictEqual(typeof Promise, 'function');
});
it('should have a then method', function () {
const promise = new Promise(() => {});
assert.strictEqual(typeof promise.then, 'function');
});
it('should call onFulfilled when the Promise is resolved', function (done) {
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success');
}, 10);
});
promise.then(function (value) {
assert.strictEqual(value, 'success');
done();
});
});
it('should call onRejected when the Promise is rejected', function (done) {
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
reject('error');
}, 10);
});
promise.then(null, function (reason) {
assert.strictEqual(reason, 'error');
done();
});
});
it('should chain then calls', function (done) {
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success');
}, 10);
});
promise.then(function (value) {
return value + '!';
}).then(function (value) {
assert.strictEqual(value, 'success!');
done();
});
});
it('should handle errors in onFulfilled and onRejected', function (done) {
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success');
}, 10);
});
promise.then(function () {
throw new Error('error');
}).then(null, function (reason) {
assert.strictEqual(reason.message, 'error');
done();
});
});
it('should not call onFulfilled or onRejected more than once', function (done) {
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success');
}, 10);
});
promise.then(function () {
done();
});
promise.then(function () {
assert.fail('onFulfilled should not be called more than once');
});
});
});
上面的单元测试涵盖了Promise A+规范中的大部分要求。您可以使用这些测试来验证您手写的Promise是否符合规范。
结语
本文带领您一步一步地手写了一个Promise,并根据Promise A+规范对其实施了测试。通过本教程,您应该对Promise及其底层机制有了更深入的理解。如果您对Promise有更多的疑问,可以查阅Promise A+规范,或在网上搜索相关资料。