一步步写一个相符Promise/A+范例的库

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 文件名
    原文作者:ReneeTsang
    原文地址: https://segmentfault.com/a/1190000013820476
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞