美文网首页前端基础
JavaScript异步处理——Promise

JavaScript异步处理——Promise

作者: Luigi_Lin | 来源:发表于2019-03-26 00:32 被阅读0次

    Promise是一种异步编程解决方案,可以使异步代码更加优雅。

    例如,我们需要进行这么一个操作:

    1. 向一个url获取一个名字
    2. 根据这个名字获取一个数据
    3. 根据这个数据获取到我们需要结果

    使用回调函数:

    get(url, function(name){
      get(name, function(data){
        get(data, function(result){
          console.log(result);
        }, errHanler)
      }, errHanler)
    }, errHanler)
    
    function errHanler(err){
      console.error(err);
    }
    

    使用Promise:

    get(url).then((name)=>{
      return get(name);
    }).then((data)=>{
      return get(data);
    }).then((result)=>{
      console.log(result);
    }).catch((err)=>{
      console.error(err);
    })
    

    使用promise可以避免层层嵌套的情况。除此之外,ES6中的Promise还有all、race等方便的操作。(ES6 Promise详细介绍)

    ES6的Promise是Promise A+规范的一种实现。(Promise A+ 规范翻译)

    现在试着自己实现一个Promise。

    首先一个promise拥有属性状态,初始时为Pennding,且可迁移到FulfilledRejected
    一个promise必须拥有then方法,并可通过then访问它的值/拒因

    class P {
        constructor() {
            this[Symbol.for("PromiseStatus")] = "pennding";
            this[Symbol.for("PromiseValue")] = undefined;
        }
    
        then(onFulfilled, onRejected) {
            const status = this[Symbol.for("PromiseStatus")];
    
            if (status == "pennding") {
                this.onFulfilled = typeof onFulfilled == 'function' ? onFulfilled : null;
                this.onRejected = typeof onRejected == 'function' ? onRejected : null;
            } else if (status == "fulfilled") {
                onFulfilled(this[Symbol.for("PromiseValue")]);
            } else if (status == "rejected") {
                onFulfilled(this[Symbol.for("PromiseValue")]);
            }
        }
    }
    

    promise有resolve、reject方法,将promise的状态分别迁移为FulfilledRejected。promise的状态只能改变一次。
    然后promise构造函数接收一个函数作为参数,并往该函数传入resolvereject

    class P {
        constructor() {
            this[Symbol.for("PromiseStatus")] = "pennding";
            this[Symbol.for("PromiseValue")] = undefined;
    
            if (typeof fn !== "function") {
                throw new TypeError(`Promise resolver ${typeof fn} is not a function`);
            }
            fn(this.resolve.bind(this), this.reject.bind(this));
        }
    
        resolve(data) {
            if (this[Symbol.for("PromiseStatus")] == "pennding") {
                this[Symbol.for("PromiseStatus")] = "fulfilled";
                this[Symbol.for("PromiseValue")] = data;            
                this.onFulfilled(data);
            }
        }
    
        reject(reason) {
            if (this[Symbol.for("PromiseStatus")] == "pennding") {
                this[Symbol.for("PromiseStatus")] = "rejected";
                this[Symbol.for("PromiseValue")] = reason;            
                this.onRejected(reason);
            }
        }
    }
    

    为了保证onFulfilled和onRejected异步执行,resove或reject被调用时不能马上调用,需要在当前一轮事件循环结束后再调用onFulfilled/onRejected。可通过setTimeout来实现

    resolve(data) {
        if (this[Symbol.for("PromiseStatus")] == "pennding") {
            this[Symbol.for("PromiseStatus")] = "fulfilled";
            this[Symbol.for("PromiseValue")] = data;
            setTimeout(() => {
                this.onFulfilled(data);
            });
        }
    }
    
    

    then方法可以被连续调用,所以需要增加onFulfilledList、onRejectedList两个数组,再resolve/reject被调用时遍历数组执行。
    最后,then方法会返回一个的promise,并将onFulfilled/onRejected中的返回值传递给新promise。

    最终版:

      class P {
    
            constructor(fn) {
                this[Symbol.for("PromiseStatus")] = "pennding";
                this[Symbol.for("PromiseValue")] = undefined;
    
                this.onFulfilledList = [];
                this.onRejectedList = [];
    
                if (typeof fn !== "function") {
                    throw new TypeError(`Promise resolver ${typeof fn} is not a function`);
                }
                fn(this.resolve.bind(this), this.reject.bind(this));
            }
    
            resolve(data) {
                if (this[Symbol.for("PromiseStatus")] == "pennding") {
                    this[Symbol.for("PromiseStatus")] = "fulfilled";
                    this[Symbol.for("PromiseValue")] = data;
    
                    for (let onFulfilled of this.onFulfilledList) {
                        onFulfilled && setTimeout(() => {
                            onFulfilled(data);
                        });
                    }
                }
            }
    
            reject(reason) {
                if (this[Symbol.for("PromiseStatus")] == "pennding") {
                    this[Symbol.for("PromiseStatus")] = "rejected";
                    this[Symbol.for("PromiseValue")] = reason;
    
                    for (let onRejected of this.onRejectedList) {
                        onRejected && setTimeout(() => {
                            onRejected(reason);
                        });
                    }
    
                }
            }
    
            then(onFulfilled, onRejected) {
                const status = this[Symbol.for("PromiseStatus")];
                let nextPromise = null;
    
                if (status == "pennding") {
                    nextPromise = new P((onFulfilledNext, onRejectedNext) => {
                        this.onFulfilledList.push(function (data) {
                            fulfill(onFulfilledNext, onRejectedNext, data);
                        });
    
                        this.onRejectedList.push(function (data) {
                            reject(onRejectedNext, data);
                        });
                    })
                } else if (status == "fulfilled") {
                    nextPromise = new P((onFulfilledNext, onRejectedNext) => {
                        const data = this[Symbol.for("PromiseValue")];
                        try {
                            onFulfilled(data);
                            fulfill(onFulfilledNext, onRejectedNext, data);
                        } catch (error) {
                            onRejected(error);
                            reject(onRejectedNext, error);
                        }
                    })
                } else if (status == "rejected") {
                    nextPromise = new P((onFulfilledNext, onRejectedNext) => {
                        const data = this[Symbol.for("PromiseValue")];
                        onRejected(data);
                        reject(onRejectedNext, data);
                    })
                }
    
                return nextPromise;
    
                function fulfill(onFulfilledNext, onRejectedNext, data){
                    try {                    
                        if (typeof onFulfilled === 'function') {
                            const x = onFulfilled(data);
                            onFulfilledNext(x);
                        }else{
                            onFulfilledNext(data);
                        }
                    } catch (e) {
                        onRejectedNext(e);
                    }
                }
    
                function reject(onRejectedNext, data){
                    try {
                        
                        if (typeof onRejected === 'function') {
                            const x = onRejected(data);
                            onRejectedNext(x);
                        }else{
                            onRejectedNext(data);
                        }
                    } catch (e) {
                        onRejectedNext(e);
                    }
                }
                
            }
    
            catch(onRejected) {
                return this.then(undefined, onRejected);
            }
    
        }
    

    相关文章

      网友评论

        本文标题:JavaScript异步处理——Promise

        本文链接:https://www.haomeiwen.com/subject/unfwvqtx.html