Promise本意是许诺,在递次中的意义就是许诺我过一段时间后会给你一个效果。
ES6 中采用了 Promise/A+ 范例,Promise 完成之前,固然要先相识 Promise/A+ 范例,范例地点https://promisesaplus.com/。
我们依据 Promise/A+ 范例,能够写一个简朴的Promise库。
每一步都只管写的细致,所以代码很长很罗嗦。
1.完成Promise基础的要领
- Promise是一个类,需要通报一个executor函数,函数里有两个参数resolve和reject,挪用resolve代表胜利,挪用reject代表失利
- Promise有三种状况:默许状况是守候状况pending,胜利resolved,失利rejected
运用例子
let Promise = require('./Promise');
// Promise是一个类,需要通报一个executor函数,这个函数我们称之为实行函数,函数中有两个参数resolve和reject他们也是函数,挪用resolve示意胜利,挪用reject示意失利
let promise = new Promise(function(resolve,reject){
// 胜利就不会再挪用失利,默许状况是守候状况pending
resolve('ok');
reject('faild');
});
// then是原型上的一个要领吸收两个参数分别是胜利的回折衷失利的回调
promise.then(function(data){// 挪用resolve后会实行胜利的回调,挪用reject后会实行失利的回调
console.log(data);
},function(err){
console.log(err);
});
完成对应的Promise库代码
function Promise(executor) { // Promise中需要吸收一个实行函数executor
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
2.异步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库代码
function Promise(executor) {
self.status = 'pending';
self.value = undefined;
self.reason = undefined;
+ self.onResolvedCallbacks = []; // 胜利回调寄存的处所
+ self.onRejectedCallbacks = [];// 失利回调寄存的处所
function resolve(value) {
if(self.status === 'pending'){
self.value = value;
self.status = 'resolved';
+ // 顺次实行胜利的回调
+ self.onResolvedCallbacks.forEach(item=>item());
}
}
function reject(reason) {
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);
+ });
+ }
}
3.Promise链式挪用
- 假如当前promise已进入胜利的回调,回调中发作了非常返回this的话,那末当前的promise的状况没法更改到失利台!所以promise完成链式挪用,返回的并非this而是一个新的promise。
实行回调中
- 假如返回的是一个一般的值,会将效果传入下一次then的胜利回调中
- 假如发作毛病会被下一次then的失利回调捕捉
- 假如返回的是promise看这个promise是胜利照样失利,对应挪用下一次的then
所以写一个resolvePromise要领,这是promise中最主要的要领,用来剖析then返回的效果
- 有些人能够胜利失利同时挪用,假如两个都挪用,用第一个挪用的,不允许同时挪用。
运用例子
promise.then(function(data){
throw Error('出错了');// 当前promise已胜利了,胜利就不会再失利
return 'renee'
}).then(null,function(err){ // 假如返回的是同一个promise那末还怎样走向失利呢?所以必需要返回一个新的promise
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;
}
function resolvePromise(promise2, x, resolve, reject) {
//x是返回的效果,假如promise和then中返回的promise是同一个,是不科学的,要报错
if(promise2===x){
return reject(new Error('轮回援用'))
}
if(x!==null&&(typeof x === 'object'|| typeof x === 'function')){
let called; //示意是不是挪用过胜利或许失利
try{
let then=x.then;
//假如then是函数,申明是promise,我们要让promise实行
if(typeof then==='function'){
then.call(x,function(y){
if(called)return; //假如挪用过直接return
called=true;
//假如resolve的效果依旧是promise那就继承剖析
},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);
}
}
4.值的穿透
- 在范例中定义then函数能够不传参,不传参默许会将胜利的效果和失利的效果继承向下通报
运用例子
promise.then().then().then(function(data){
console.log(data)
})
完成对应的Promise库代码
Promise.prototype.then = function (onFufilled, onRejected) {
//失利和胜利默许不传给一个函数
+ onFufilled = typeof onFufilled === 'function'?onFufilled:function(value){
+ return value
+ }
+ onRejected = typeof onRejected === 'function'?onRejected:function(err){
+ throw err
+ }
5.测试
别的能够经由过程装置一个插件来对完成的promise举行范例测试。
npm(cnpm) i -g promises-aplus-tests
promises-aplus-tests 文件名