基本框架
首先打开Promises/A+规范,根据如下要求构建代码框架。
- “promise” is an object or function with a then method whose behavior conforms to this specification.
- A promise must provide a then method to access its current or eventual value or reason.
class myPromise {
constructor(){
}
resolve(){
}
reject(){
}
then(){
}
}
State
根据promise的使用方法可以知道promise共有三种状态,相关规范如下:
- A promise must be in one of three states: pending, fulfilled, or rejected.
在class最上方加入相关代码
static PENDING = 'pending';
static FULFILLED = 'fulfilled';
static REJECTED = 'rejected';
初始化
一个promise对象在constructor调用时进行初始化,需要初始化其state和result
onFulfilledCallbacks/onRejectedCallbacks用于保存then方法传入的参数
this.PromiseState = myPromise.PENDING;
this.PromiseResult = null;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
resolve 和 reject
在给constuctor传入的函数内调用resolve和reject改变promise状态,在resolve/reject执行时还会执行then方法传入的相关参数。
- When pending, a promise: may transition to either the fulfilled or rejected state.
- When fulfilled, a promise: must not transition to any other state. must have a value, which must not change.
- When rejected, a promise: must not transition to any other state. must have a reason, which must not change.
resolve(result) {
if (this.PromiseState === myPromise.PENDING) {
setTimeout(() => {
this.PromiseState = myPromise.FULFILLED;
this.PromiseResult = result;
this.onFulfilledCallbacks.forEach(callback=> {
callback(result)
})
});
}
}
reject(reason) {
if (this.PromiseState === myPromise.PENDING) {
setTimeout(() => {
this.PromiseState = myPromise.REJECTED;
this.PromiseResult = reason;
this.onRejectedCallbacks.forEach(callback=> {
callback(reason)
})
});
}
}
解释一下resolve/reject内部异步的原因:
Promise/A+有提到 onFulfilled or onRejected must not be called until the execution context stack contains only platform code.
onFulfilled/onRejected作为then传入的参数需要在所有同步代码执行后才能执行,因此异步的resolve/reject可以保证其执行顺序
then
then方法接受两个参数,这两个参数会在promise状态改变后执行,如果参数不是函数,则应该被忽略
- Both onFulfilled and onRejected are optional arguments
- If onFulfilled is not a function, it must be ignored
- If onRejected is not a function, it must be ignored
onFulfilled = typeof onFulfilled === 'function' onFulfilled : value => value;
onRejected = typeof onRejected === 'function' ? onRejecte: e => {throw e};
其次我们知道then方法可以被多次调用,也就是说then方法一定会返回一个promise,then方法的代码框架应该如下
- then may be called multiple times on the same promise.
let promise2 = new myPromise((resolve, reject) => {
//some code
}
return promise2
then方法返回的promise(下面成为promise2)状态由onFulfilled/onRejected的返回值决定,该函数的返回值由三种情况:
- 简单值,如果是简单值(number,boolean,普通object等),则promise2的值也为简单值
- promise对象,如果onFulfilled/onRejected也返回一个promise,则promise2的状态和值将由新返回的promise决定(这个决定的过程成为resolvePromise)
- thenable对象,如果返回的对象拥有一个then函数,则尝试resolve过程
参考A+相关标准:
- If either onFulfilled or onRejected returns a value x, run the Promise Resolution Procedure [[Resolve]](promise2, x).
- If either onFulfilled or onRejected throws an exception e, promise2 must be rejected with e as the reason.
在then内加入如下代码
if (this.PromiseState === myPromise.FULFILLED) {
setTimeout(() => {
try {
let x = onFulfilled(this.PromiseResult);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
});
} else if (this.PromiseState === myPromise.REJECTED) {
setTimeout(() => {
try {
let x = onRejected(this.PromiseResult);
//resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}
});
} else {
this.onFulfilledCallbacks.push(() => {
setTimeout(() => {
try {
let x = onFulfilled(this.PromiseResult);
//resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e);
}
});
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onRejected(this.PromiseResult);
//resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
});
});
}
这里根据promise的三种状态分为三种情况:
- promise处于pending状态则将两个参数反别放入对应数组等待执行
- promise处于fulfilled状态,则立刻执行onFulfilled
- promise处于rejected状态,则执行onRejected
resolvePromise
resolvePromise处理onFulfilled/onRejected返回值的三种情况,如果onFulfilled/onRejected依然返回promise则继续执行resolve过程,也就是说then方法返回的promise状态由onFulfilled/onRejected “最深层” 的promise决定
function resolvePromise(promise2, x, resolve, reject) {
if (x === promise2) {
return reject(new TypeError('Chaining cycle detected for promise'));
}
// promise
if (x instanceof myPromise) {
if (x.PromiseState === myPromise.PENDING) {
x.then(y => {
resolvePromise(promise2, y, resolve, reject)
}, reject);
} else if (x.PromiseState === myPromise.FULFILLED) {
resolve(x.PromiseResult);
} else if (x.PromiseState === myPromise.REJECTED) {
reject(x.PromiseResult);
}
} else if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
//thenable
let then
try {
then = x.then;
} catch (e) {
return reject(e);
}
if (typeof then === 'function') {
let called = false;
try {
then.call(x,
(a) =>{
if(called){
return
}
called = true
resolvePromise(promise2, a, resolve, reject)
},
(b) =>{
if(called){
return
}
called = true
reject(b)
})
} catch (e) {
if (called) return;
called = true;
reject(e);
}
} else {
resolve(x);
}
} else {
//简单值
return resolve(x);
}
}
called的作用:thenable对象并不是promise,但是依然要求其遵守相关规范(状态不可变且回调函数只能执行一次)
完整代码
class myPromise {
static PENDING = 'pending';
static FULFILLED = 'fulfilled';
static REJECTED = 'rejected';
constructor(func) {
this.PromiseState = myPromise.PENDING;
this.PromiseResult = null;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
try {
func(this.resolve.bind(this), this.reject.bind(this));
} catch (error) {
this.reject(error)
}
}
resolve(result) {
if (this.PromiseState === myPromise.PENDING) {
setTimeout(() => {
this.PromiseState = myPromise.FULFILLED;
this.PromiseResult = result;
this.onFulfilledCallbacks.forEach(callback => {
callback(result)
})
});
}
}
reject(reason) {
if (this.PromiseState === myPromise.PENDING) {
setTimeout(() => {
this.PromiseState = myPromise.REJECTED;
this.PromiseResult = reason;
this.onRejectedCallbacks.forEach(callback => {
callback(reason)
})
});
}
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
onRejected = typeof onRejected === 'function' ? onRejected : reason => {
throw reason;
};
let promise2 = new myPromise((resolve, reject) => {
if (this.PromiseState === myPromise.FULFILLED) {
setTimeout(() => {
try {
let x = onFulfilled(this.PromiseResult);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
});
} else if (this.PromiseState === myPromise.REJECTED) {
setTimeout(() => {
try {
let x = onRejected(this.PromiseResult);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}
});
} else {
this.onFulfilledCallbacks.push(() => {
setTimeout(() => {
try {
let x = onFulfilled(this.PromiseResult);
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e);
}
});
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onRejected(this.PromiseResult);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
});
});
}
})
return promise2
}
}
function resolvePromise(promise2, x, resolve, reject) {
if (x === promise2) {
return reject(new TypeError('Chaining cycle detected for promise'));
}
if (x instanceof myPromise) {
if (x.PromiseState === myPromise.PENDING) {
x.then(y => {
resolvePromise(promise2, y, resolve, reject)
}, reject);
} else if (x.PromiseState === myPromise.FULFILLED) {
resolve(x.PromiseResult);
} else if (x.PromiseState === myPromise.REJECTED) {
reject(x.PromiseResult);
}
} else if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
let then
try {
then = x.then;
} catch (e) {
return reject(e);
}
if (typeof then === 'function') {
let called = false;
try {
then.call(x,
(a) =>{
if(called){
return
}
called = true
resolvePromise(promise2, a, resolve, reject)
},
(b) =>{
if(called){
return
}
called = true
reject(b)
})
} catch (e) {
if (called) return;
called = true;
reject(e);
}
} else {
resolve(x);
}
} else {
return resolve(x);
}
}
测试
首先在代码最后面加上这个
myPromise.deferred = function () {
let result = {};
result.promise = new myPromise((resolve, reject) => {
result.resolve = resolve;
result.reject = reject;
});
return result;
}
module.exports = myPromise;
安装及运行测试工具
npm i promises-aplus-tests --save-dev
npm run promises-aplus-tests myPromise