用 ES5 语法 实现一个 符合 Promise/A+ 规范 的完整 Promise,附 Promise.all/race/finally 等静态方法,面试手写无压力。
一、手写核心 Promise(符合 A+)
1. 结构
js
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
function MyPromise(executor) {
this.state = PENDING;
this.value = undefined;
this.reason = undefined;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
const resolve = value => {
if (this.state === PENDING) {
this.state = FULFILLED;
this.value = value;
this.onFulfilledCallbacks.forEach(fn => fn());
}
};
const reject = reason => {
if (this.state === PENDING) {
this.state = REJECTED;
this.reason = reason;
this.onRejectedCallbacks.forEach(fn => fn());
}
};
try {
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
2. then 方法(链式核心)
js
MyPromise.prototype.then = function (onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val;
onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err; };
return new MyPromise((resolve, reject) => {
const handle = () => {
try {
const result = this.state === FULFILLED
? onFulfilled(this.value)
: onRejected(this.reason);
resolvePromise(result, resolve, reject);
} catch (err) {
reject(err);
}
};
if (this.state === PENDING) {
this.onFulfilledCallbacks.push(handle);
this.onRejectedCallbacks.push(handle);
} else {
setTimeout(handle, 0);
}
});
};
function resolvePromise(result, resolve, reject) {
if (result instanceof MyPromise) {
result.then(resolve, reject);
} else {
resolve(result);
}
}
二、静态方法全家桶
1. Promise.resolve / reject
js
MyPromise.resolve = value => new MyPromise(resolve => resolve(value));
MyPromise.reject = reason => new MyPromise((_, reject) => reject(reason));
2. Promise.all(并发等待)
js
MyPromise.all = function (promises) {
return new MyPromise((resolve, reject) => {
let count = 0;
const results = [];
promises.forEach((p, i) => {
MyPromise.resolve(p).then(
val => {
results[i] = val;
if (++count === promises.length) resolve(results);
},
reject
);
});
});
};
3. Promise.race(谁先完成用谁)
js
MyPromise.race = function (promises) {
return new MyPromise((resolve, reject) => {
promises.forEach(p => MyPromise.resolve(p).then(resolve, reject));
});
};
4. Promise.finally(无论成功失败都执行)
js
MyPromise.prototype.finally = function (callback) {
return this.then(
val => MyPromise.resolve(callback()).then(() => val),
err => MyPromise.resolve(callback()).then(() => { throw err; })
);
};
三、完整测试用例
js
// 1. 基本链式
new MyPromise(resolve => resolve(1))
.then(val => val + 1)
.then(val => console.log(val)); // 2
// 2. 并发
MyPromise.all([
new MyPromise(resolve => setTimeout(() => resolve('a'), 100)),
new MyPromise(resolve => setTimeout(() => resolve('b'), 200))
]).then(console.log); // ['a', 'b']