欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

es6 --- > 手写一个promise

程序员文章站 2022-06-30 19:11:54
...

一个promise实例:

var getJSON = function(url) {
    var promise = new Promise(function(resolve, reject) {
        // XHR对象发现ajax请求
        var client = new XMLHttpReqeust();
        client.open("GET", url);
        client.onreadystatechange = handler;
        client.responseType = "json";
        client.setRequestHeader("Accept", "application/json");
        client.send();
         
        function hanlder(){
            if (this.readyState !== 4) {
                return;
            }
            if (this.status === 200) {
                resolve(this.response);
            } else {
                reject(new Error(this.statusText));
            }
        };
    });
    return promise;
}
getJSON("/posts.json").then(function(json) {
    console.log("Content: " + json);
}, function(error) {
    console.error("出错了!', error);
});

上述在调用new Promise时,传递了一个函数function(resolve, reject),此函数在规范中被称为exector执行器.
所以,首先:需传入一个exector执行器:

function Promise(exector) {
    //...
}

确定Promise内部exector的作用:
可以看出原生的exector中传入了2个参数,resolve和reject.第一个代表成功,第二个代表失败.

function Promise(exector) {
    let self = this;
    this.value = undefined;
    this.reason = reason;
    
    // 执行成功
    function resolve(value) {
        self.value = value;
    }
    
    // 执行失败
    function reject(reason) {
        self.reason = reason;
    }
     
    exector(resolve, reject);
}

添加状态:
promise的执行过程是不可逆,因此需要一个status来记录其状态,初始时为padding,成功了为resolve,失败了为reject

function Promise(exector) {
    let self = this;
    this.status = "padding";
    this.value = value;
    this.reason = reason;
   
    // 成功
    function resolve(value) {
        if(self.status === "padding") {
            self.value = value;
            self.status = "resolved";
        }
    }
     
    // 失败
    function  reject(reason) {
        if(self.status === "padding") {
            self.reason = reason;
            self.status = "reject";
        }
    }
   
    // 对异常的处理
    try {
        exector(resolve, reject);
    } catch(e) {
        reject(e)
    }
}

原型上添加then方法:
注意到Promise实例的使用是p.then(onFulfilled, onRejected),可以在前面定义的Promise的原型上添加then方法.

Promise.prototype.then = function(onFulfilled, onRejected) {
    let self = this;
    if(this.status === "resolved") {
        onFulfilled(self.value);
    }
     
    if(this.status === "rejected") {
        onRejected(self.value);
    }
}

新增2个数组完成异步操作:
上面编写的Promise的调用是同步的,但一般都是异步使用Promise,故需在对Promise和其原型进行一定的修改.
如果异步,则处于padding状态,将回调函数fn保存在数组中!

function Promise(exector) {
    let self = this;
    this.status = "padding";
    this.value = undefined;
    this.reason = undefined;
    
    // 存储then中成功的回调函数
    this.onResolvedCallbacks = [];
    // 存储then中失败的回调函数
    this.onRejectedCallbacks = [];
   
   // 成功执行
   function resolve(value) {
       if(self.status === "padding") {
           self.value = value;
           self.status = "resolved";
            
           // 成功后遍历then中成功的所有回调函数
           self.onResolvedCallbacks.forEach(fn => fn());
       }
   }
    
   // 失败执行
   function reject(reason) {
       if(self.status === "padding") {
           self.reason = reason;
           self.status = "rejected";
            
           // 失败后遍历then中失败的所有回调函数
           self.onRejectedCallbacks.forEach(fn => fn());
       }
   }
    
   // 对异常进行处理
   try {
       exector(resolve, reject);
   } catch(e) {
       reject(e)
   }
}

// Promise.prototype.then
Promise.prototype.then = function(onFulfilled, onRejected) {
    let self = this;
    
    // 成功
    if (this.status === "rejected") {
        onFulfilled(self.value);
    }
    // 失败
    if (this.status === "resolved") {
        onRejected(self.reason);
    }
    // padding
    if (this.status === "padding") {
        // 推进onResolvedCallbacks数组
        this.onResolvedCallbacks.push( () => {
            onFulfilled(self.value);
        })
        this.onRejectedCallbacks.push( () => {
            onRejected(self.reason);
        })
    }
}

参考《ES6标准入门》(第3版) P276
参考 https://www.jianshu.com/p/4b126518c26d

相关标签: 跪着敲完的