Promise是JavaScript的一个重点,本文主要记录我手写ES6 Promise的思路,仅实现Promise及其.then方法,最下方附带完整代码,希望对你有所帮助
Promise
在传统的项目中,使用异步操作只能不断地通过callback来进行回调,在复杂的项目中就容易产生回调地狱的问题,这时候ES6引入了几个异步解决方案,其中Promise就包含其中,极大地改善了异步操作
Promise/A+中并未规范race、all等方法,这些都是ES6的规范,本文主要实现Promise构建及其.then方法
手写Promise
promise对象接收的是callback,callback接收两个参数resolve和reject 当我们在执行callback的时候,会调用定义的resolve和reject,这两个函数需要我们定义在Promise内部 然后resolve和reject会改变promise的状态,我们需要一个state来记录当前promise的状态
function MyPromise(callback){
let self = this;
let state = null;//null表示pending,false表示rejected,true表示fulfilled
//保留Promise完成时的结果值或者错误信息,让他在后续还能用上
let param = null;
//resolve方法
function resolve(data) {
state = true;
param = data;
}
//reject方法
function reject(data) {
state = false;
param = data;
}
}
但是我们这里缺少了Promise的重要内容then方法 then方法接收的参数为onFulfilled和onRejected,都为可选参数,在期约分别进入兑现和拒绝状态时执行,在规范中提到传进来的参数只能是函数,如果想要跳过某一个参数可以先传入null then方法返回的也是一个Promise对象,这是链式调用的核心
//then方法
this.then = function (onFulfilled, onRejected) {
//返回一个新的promise对象,链式调用的核心
return new self.constructor(function (resolve, reject) {
......
});
};
then方法的实现
这时候需要根据状态进行判断执行哪个函数,但是如果为pending状态呢
Promise的状态我们无法实时获取,因此我们只能在执行状态改变的时候,也就是在resolve和reject两个方法中,同时执行onFulfilled或者onRejected,但是我们这里没有这两个函数,所以需要在外部增加四个变量分别记录onFulfilled和onRejected,以及then方法返回的新promise对象的resolve和reject
function MyPromise(callback) {
........
//then方法返回的promise对象的resolve和reject
+ let nextResolve = null;
+ let nextReject = null;
//记录then方法的回调函数
+ let asynconFulfilled = null;
+ let asynconRejected = null;
//执行并改变promise对象状态
callback(resolve, reject);
//then方法
this.then = function (onFulfilled, onRejected) {
//返回一个新的promise对象,链式调用的核心
return new self.constructor(function (resolve, reject) {
+ //判断异步代码是否执行完毕
+ //若执行完毕就在then方法中立即执行,否则将四个参数记录下来,等待state就绪后再执行
+ if (state === true) {
+ doAsynconFulfilled(onFulfilled, resolve, reject);
+ } else if (state === false) {
+ doAsynconRejected(onRejected, resolve, reject);
+ } else {
+ nextResolve = resolve;
+ nextReject = reject;
+ asynconFulfilled = onFulfilled;
+ asynconRejected = onRejected;
+ }
});
};
//resolve方法
function resolve(data) {
state = true;
param = data;
+ nextResolve(asynconFulfilled(param))
}
//reject方法
function reject(data) {
state = false;
param = data;
+ nextReject(asynconRejected(param))
}
}
这里我画个图可能会更好理解一点
其实就两个时间线:then 在 resolve 之前 调用(pending 状态),then 在 resolve 之后 调用(fulfilled/rejected 状态)
但是我们少判断了一点,如果then返回的为promise对象,如果后面还有then方法需要等待前一个then中的prmise状态变为兑现活拒绝,才能执行 这里传入的onFulfilled和onRejected和then方法传进来的参数必须为函数,如果不是则忽略掉
//resolve方法
function resolve(data) {
state = true;
param = data;
if (nextResolve) {
doAsynconFulfilled(asynconFulfilled, nextResolve, nextReject);
}
}
//reject方法
function reject(data) {
state = false;
param = data;
if (nextReject) {
doAsynconRejected(asynconRejected, nextResolve, nextReject);
}
}
function doAsynconFulfilled(onFulfilled, resolve, reject) {
//onFulfilled和onRejected只有再执行环境堆栈仅包含平台代码时才可被调用,将其放在setTimeout中执行
//平台代码指的是JavaScript宿主环境(如nodejs或浏览器)提供的代码(比如setTimeout),而非用户定义的代码
//确保then回调总是异步执行,及时Promise是同步resolved或rejected
window.setTimeout(function () {
//判断onFulfilled是否为函数,不是则忽略
if (typeof onFulfilled === "function") {
let promise = onFulfilled(param);
if (promise === undefined) {
//如果没有显式返回语句,Promise.resolve会包装默认的返回值undefined
//如果onFulfilled没有返回值,则直接resolve
resolve(promise);
} else if (promise.constructor === self.constructor) {
//等待传递进行的promise执行完毕,再根据传递进行的promise的状态来决定是resolve还是reject
promise.then(
function (param) {
resolve(param);
},
function (param) {
reject(param)
}
);
} else {
//执行then方法返回的对象的resolve方法
resolve(promise);
}
} else {
//传递参数
resolve(param);
}
}, 0);
}
function doAsynconRejected(onRejected, resolve, reject) {
window.setTimeout(function () {
if (typeof onRejected === "function") {
let promise = onRejected(param);
if (promise === undefined) {
reject(param);
} else if (promise.constructor === self.constructor) {
promise.then(
function (param) {
resolve(param);
},
function (param) {
reject(param);
}
);
} else {
reject(promise);
}
} else {
//传递参数
reject(param);
}
}, 0);
}
最终代码
function MyPromise(callback) {
let self = this;
let state = null;
//记录resolve的参数
let param = null;
//then方法返回的promise对象的resolve和reject
let nextResolve = null;
let nextReject = null;
//记录then方法的回调函数
let asynconFulfilled = null;
let asynconRejected = null;
//执行并改变promise对象状态
callback(resolve, reject);
//then方法
this.then = function (onFulfilled, onRejected) {
//返回一个新的promise对象,链式调用的核心
return new self.constructor(function (resolve, reject) {
//判断异步代码是否执行完毕
//若执行完毕就在then方法中立即执行,否则将四个参数记录下来,等待state就绪后再执行doAsyn函数
if (state === true) {
doAsynconFulfilled(onFulfilled, resolve, reject);
} else if (state === false) {
doAsynconRejected(onRejected, resolve, reject);
} else {
nextResolve = resolve;
nextReject = reject;
asynconFulfilled = onFulfilled;
asynconRejected = onRejected;
}
});
};
//resolve方法
function resolve(data) {
state = true;
param = data;
if (nextResolve) {
doAsynconFulfilled(asynconFulfilled, nextResolve, nextReject);
}
}
//reject方法
function reject(data) {
state = false;
param = data;
if (nextReject) {
doAsynconRejected(asynconRejected, nextResolve, nextReject);
}
}
function doAsynconFulfilled(onFulfilled, resolve, reject) {
//onFulfilled和onRejected只有再执行环境堆栈仅包含平台代码时才可被调用,将其放在setTimeout中执行
//平台代码指的是JavaScript宿主环境(如nodejs或浏览器)提供的代码(比如setTimeout),而非用户定义的代码
//确保then回调总是异步执行,及时Promise是同步resolved或rejected
window.setTimeout(function () {
//判断onFulfilled是否为函数,不是则忽略
if (typeof onFulfilled === "function") {
let promise = onFulfilled(param);
if (promise === undefined) {
//如果没有显式返回语句,Promise.resolve会包装默认的返回值undefined
//如果onFulfilled没有返回值,则直接resolve
resolve(promise);
} else if (promise.constructor === self.constructor) {
//等待传递进行的promise执行完毕,再根据传递进行的promise的状态来决定是resolve还是reject
promise.then(
function (param) {
resolve(param);
},
function (param) {
reject(param);
}
);
} else {
//执行then方法返回的对象的resolve方法
resolve(promise);
}
} else {
//传递参数
resolve(param);
}
}, 0);
}
function doAsynconRejected(onRejected, resolve, reject) {
window.setTimeout(function () {
if (typeof onRejected === "function") {
let promise = onRejected(param);
if (promise === undefined) {
reject(param);
} else if (promise.constructor === self.constructor) {
promise.then(
function (param) {
resolve(param);
},
function (param) {
reject(param);
}
);
} else {
reject(promise);
}
} else {
//传递参数
reject(param);
}
}, 0);
}
}