为了更好的了解promise实现,我们一步步来完善promise库。我们先来写一个基础用例,通过用例来看promise是如何实现的!
let Promise = require('./Promise');
// Promise是一个类,需要传递一个函数,这个函数我们称之为执行函数,函数中有两个参数resolve和reject他们也是函数,调用resolve表示成功,调用reject表示失败
let promise = new Promise(function(resolve,reject){
// 成功就不会再调用失败,默认状态是等待状态
resolve('ok');
reject('faild');
});
// then是原型上的一个方法接收两个参数分别是成功的回调和失败的回调
promise.then(function(data){// 调用resolve后会执行成功的回调,调用reject后会执行失败的回调
console.log(data);
},function(err){
console.log(err);
});
实现对应的Promise库代码
function Promise(executor) {
// Promise中需要接收一个执行函数
let self = this;
self.status = 'pending'; //默认是pending状态
self.value = undefined; // 成功的原因
self.reason = undefined; // 失败的原因
function resolve(value) { // 调用resolve 会传入为什么成功
if(self.status === 'pending'){ // 只有再pending才能转换成功态
self.value = value; // 将成功的原因保存下来
self.status = 'resolved'; // 状态改成成功态
}
}
function reject(reason) { // 调用reject会传入为什么失败
if(self.status === 'pending'){
self.reason = reason;
self.status = 'rejected';
}
}
try {
executor(resolve, reject);// executor中需要传入resolve和reject
} catch (e) {
// 如果executor执行发生异常,表示当前的promise是失败态
reject(e);
}
}
// then中要传入成功的回调和失败的回调
Promise.prototype.then = function(onFufilled,onRejected){
let self = this;
// 如果要是成功就调用成功的回调,并将成功的值传入
if(self.status === 'resolved'){
onFufilled(self.value);
}
if(self.status === 'rejected'){
onRejected(self.reason);
}
}
module.exports = Promise
在new Promise时内部可以写异步代码,并且产生的实例可以then多次
let Promise = require('./Promise');
let promise = new Promise(function(resolve,reject){
setTimeout(function(){
resolve('ok');
},1000)
});
// 当调用then时可能状态依然是pending状态,我们需要将then中的回调函数保留起来,当调用resolve或者reject时按照顺序执行
promise.then(function(data){
console.log(data);
},function(err){
console.log(err);
});
promise.then(function(data){
console.log(data);
},function(err){
console.log(err);
});
实现对应的Promise库代码
self.status = 'pending'; //默认是pending状态
self.value = undefined; // 成功的原因
self.reason = undefined; // 失败的原因
+ self.onResolvedCallbacks = []; // 成功回调存放的地方
+ self.onRejectedCallbacks = [];
function resolve(value) { // 调用resolve 会传入为什么成功
if(self.status === 'pending'){ // 只有再pending才能转换成功态
self.value = value; // 将成功的原因保存下来
self.status = 'resolved'; // 状态改成成功态
+ // 依次执行成功的回调
+ self.onResolvedCallbacks.forEach(item=>item());
}
}
function reject(reason) { // 调用reject会传入为什么失败
if(self.status === 'pending'){
self.reason = reason;
self.status = 'rejected';
+ self.onRejectedCallbacks.forEach(item=>item());
}
}
Promise.prototype.then = function(onFufilled,onRejected){
if(self.status === 'rejected'){
onRejected(self.reason);
}
+ if(self.status === 'pending'){
+ // 如果是等待态,就将成功和失败的回调放到数组中
+ self.onResolvedCallbacks.push(function(){
+ onFufilled(self.value);
+ });
+ self.onRejectedCallbacks.push(function(){
+ onRejected(self.reason);
+ });
+ }
}
module.exports = Promise
promise实现链式调用,返回的并不是this而是一个新的promise,如果当前promise已经进入成功了的回调,回调中发生了异常如果返回的仍是当前的promise那么状态无法更改到失败态!
promise.then(function(data){
throw Error('出错了');// 当前promise已经成功了
return 'zfpx'
}).then(null,function(err){ // 如果返回的是同一个promise那么还怎么走向失败呢?所以必须要返回一个新的promise
console.log(err);
})
let Promise = require('./Promise');
let promise = new Promise(function(resolve,reject){
setTimeout(function(){
resolve('ok');
},1000)
});
promise.then(function(data){
// 如果返回的是一个普通的值,会将结果传入下一次then的成功回调中
// 如果发生错误会被下一次then的失败回调捕获
// 如果返回的是promise看这个promise是成功还是失败,对应调用下一次的then
return data+',no problem';
},function(err){
console.log(err);
}).then(function(data){
console.log(data);
},function(err){
console.log(err);
});
实现对应的Promise库代码
Promise.prototype.then = function(onFufilled,onRejected){
let self = this;
+ let promise2; // promise2为then调用后返回的新promise
// 如果要是成功就调用成功的回调,并将成功的值传入
if(self.status === 'resolved'){
- onFufilled(self.value);
+ promise2 = new Promise(function(resolve,reject){
+ try{
+ // 执行时有异常发生,需要将promise2的状态置为失败态
+ let x = onFufilled(self.value);
+ // x为返回的结果
+ // resolvePromise是对当前返回值进行解析,通过解析让promise2的状态转化成成功态还是失败态
+ resolvePromise(promise2,x,resolve,reject);
+ }catch(e){
+ reject(e);
+ }
+ })
}
if(self.status === 'rejected'){
- onRejected(self.reason);
+ promise2 = new Promise(function(resolve,reject){
+ try{
+ let x = onRejected(self.reason);
+ resolvePromise(promise2,x,resolve,reject);
+ }catch(e){
+ reject(e)
+ }
+ })
}
if(self.status === 'pending'){
// 如果是等待态,就将成功和失败的回调放到数组中
+ promise2 = new Promise(function(resolve,reject){
self.onResolvedCallbacks.push(function(){
- onFufilled(self.value);
+ try{
+ let x = onFufilled(self.value);
+ resolvePromise(promise2,x,resolve,reject)
+ }catch(e){
+ reject(e);
+ }
+ })
});
self.onRejectedCallbacks.push(function(){
- onRejected(self.reason);
+ try{
+ let x = onRejected(self.reason);
+ resolvePromise(promise2,x,resolve,reject)
+ }catch(e){
+ reject(e);
+ }
});
+ })
}
+ return promise2;
}
resolvePromise是promise中最重要的方法,用来解析then返回的结果
function resolvePromise(promise2, x, resolve, reject) {
// 如果返回的promise和then中返回的promise是同一个promise,根据规范要报类型错误
// 相当于自己等待自己完成这是不科学的
if (promise2 === x) {
return reject(new TypeError('循环引用'))
}
if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
// 如果是对象可能是一个thenable(带有then方法)对象
let called; // 成功或者失败不能同时调用
try { // 如果用defineProperty定义的then方法获取时可能会有异常
let then = x.then;
// 如果then是函数,说明是promise,我们要让promse执行
if (typeof then === 'function') {
then.call(x, function (y) {
if (called) return;
called = true;
// 如果resolve的结果依旧是promise那就继续解析
resolvePromise(promise2, y, resolve, reject);
}, function (err) {
if (called) return;
called = true;
reject(err);
})
} else {
// 不是函数,x就是一个普通的对象,直接成功即可
resolve(x);
}
} catch (e) {
if (called) return;
called = true;
reject(e);
}
} else {
// 是普通值直接调用成功
resolve(x);
}
}
为了保证程序执行的一致性,规范中要求then中的方法必须在下一队列中执行
if (self.status === 'resolved') {
promise2 = new Promise(function (resolve, reject) {
- try {
- // 执行时有异常发生,需要将promise2的状态置为失败态
- let x = onFufilled(self.value);
- // x为返回的结果
- // resolvePromise是对当前返回值进行解析,通过解析让promise2的状态转化成成功态还是失败态
- resolvePromise(promise2, x, resolve, reject);
- } catch (e) {
- reject(e);
- }
+ setTimeout(function(){
+ try {
+ // 执行时有异常发生,需要将promise2的状态置为失败态
+ let x = onFufilled(self.value);
+ // x为返回的结果
+ // resolvePromise是对当前返回值进行解析,通过解析让promise2的状态转化成成功态还是失败态
+ resolvePromise(promise2, x, resolve, reject);
+ } catch (e) {
+ reject(e);
+ }
+ })
})
}
if (self.status === 'rejected') {
promise2 = new Promise(function (resolve, reject) {
- try {
- let x = onRejected(self.reason);
- resolvePromise(promise2, x, resolve, reject);
- } catch (e) {
- reject(e)
- }
+ setTimeout(function(){
+ try {
+ let x = onRejected(self.reason);
+ resolvePromise(promise2, x, resolve, reject);
+ } catch (e) {
+ reject(e)
+ }
+ })
})
}
if (self.status === 'pending') {
// 如果是等待态,就将成功和失败的回调放到数组中
promise2 = new Promise(function (resolve, reject) {
self.onResolvedCallbacks.push(function () {
- try {
- let x = onFufilled(self.value);
- resolvePromise(promise2, x, resolve, reject)
- } catch (e) {
- reject(e);
- }
+ setTimeout(function(){
+ try {
+ let x = onFufilled(self.value);
+ resolvePromise(promise2, x, resolve, reject)
+ } catch (e) {
+ reject(e);
+ }
+ })
});
self.onRejectedCallbacks.push(function () {
- try {
- let x = onRejected(self.reason);
- resolvePromise(promise2, x, resolve, reject)
- } catch (e) {
- reject(e);
- }
+ setTimeout(function(){
+ try {
+ let x = onRejected(self.reason);
+ resolvePromise(promise2, x, resolve, reject)
+ } catch (e) {
+ reject(e);
+ }
+ })
})
});
}
在规范中定义then函数可以不传参,不传参默认会将成功的结果和失败的结果继续向下传递
Promise.prototype.then = function (onFufilled, onRejected) {
+ onFufilled = typeof onFufilled === 'function'?onFufilled:function(value){
+ return value
+ }
+ onRejected = typeof onRejected === 'function'?onRejected:function(err){
+ throw err
+ }
// 这里我们可以顺便加上catch方法
Promise.prototype.catch = function(callback){
return this.then(null,callback)
}
Promise.defer是Promise的语法糖
Promise.deferred = Promise.defer = function(){
let dfd = {};
dfd.promise = new Promise(function(resolve,reject){
dfd.resolve = resolve;
dfd.reject = reject;
})
return dfd
}
看我们可以这样来使用promise了
function defer(){
let defer = Promise.defer();
setTimeout(function(){
defer.resolve('ok')
},3000);
return defer.promise
}
defer().then(function(data){
console.log(data);
})
let Promise = require('./3.async');
new Promise(function (resolve, reject) {
setTimeout(function () {
resolve(new Promise(function (resolve, reject) {
resolve('ok');
}))
}, 2000)
}).then(function (data) {
console.log(data);
});
对resolve方法进行改写
function resolve(value) { // 调用resolve 会传入为什么成功
+ if (value !== null && (typeof value === 'object' || typeof value === 'function')) {
+ if(typeof value.then === 'function'){
+ // 将当前promise成功的结果再次传回resolve函数中
+ return value.then(resolve,reject);
+ }
+ }
if (self.status === 'pending') {
我们可以用promises-aplus-tests库来测试我们的promise是否符合promiseA+规范
$ npm install promises-aplus-tests -g
promises-aplus-tests Promise.js
Promise.all = function(promises){
let i = 0; // 用来计数有多少个promise执行成功
let result = [];// 存放结果
return new Promise(function(resolve,reject){
promises.forEach(function(p,index){
p.then(function(data){
// 将结果和数组的索引对应起来
result[index] = data;
if(++i === promises.length){
// 当promise全部完成后调用all方法成功的回调
resolve(result)
}
},reject);
});
});
}
任何一个promise成功就变为成功态,失败就变为失败态
Promise.race = function (promises) {
return new Promise(function (resolve, reject) {
promises.forEach(function (p, index) {
p.then(function (data) {
resolve(data)
}, reject);
});
});
}
返回一个成功的promise
Promise.resolve = function(value){
return new Promise(function(resolve,reject){
resolve(value);
});
}
返回一个失败的promise
Promise.reject = function(reason){
return new Promise(function(resolve,reject){
reject(reason);
});
}