zoukankan      html  css  js  c++  java
  • 探究Promise的实现

      最终答案在一个类库里,地址 https://github.com/yahoo/ypromise 这个类库也有问题,就是下面这道面试题在IE9里实现不一致,类库里还是用了setTimeout。去年尝试用setTimeout(,0)来实现Promise,见Promise的实现原理 ,最后以失败告终。今天前端leader在群里放了一组面试题,最后一题

    setTimeout(function() {
      console.log(1)
    }, 0);
    new Promise(function executor(resolve) {
      console.log(2);
      for( var i=0 ; i<10000 ; i++ ) {
        i == 9999 && resolve();
      }
      console.log(3);
    }).then(function() {
      console.log(4);
    });
    console.log(5);

    romise 的 then 应当会放到当前 tick 的最后,但是还是在当前 tick 中。因此,应当先输出 5,然后再输出 4 。最后在到下一个 tick,就是 1 。

    “2 3 5 4 1”

    补充解释是最后一题 Promise 的 4 在 1 前面输出是因为 Promise.then()里面的回调属于 microtask, 会在当前 Event Loop 的最后执行, 而 SetTimeout 内的回调属于 macrotask, 会在下一个 Event Loop 中执行。

    这时候忽然发现用setTimeout来实现貌似有问题,然后东哥说当然不能用settimeout实现。promise依赖通知机制,不依赖时间,里面使用了观察者模式。这又给了我新的思路,去

    github上搜一下Promise,有一些写好的库,关键词加上中文二字,也会发现简易实现。迷你书提到了一些较好的Promsie实现,真的有不用settimeout来实现的,好好看一下。

    找到了另外一篇,promise异步编程的原理  担心作者删掉,就在这儿再贴一份(原文有错误,我这儿改正了),也可参考另外一篇。这篇也存在很大的问题,就是在只能用异步的方法,不能用同步。到底去哪找靠谱的实现呢。

    要实现promise对象,首先要考虑几个问题:

    1.promise构造函数中要实现异步对象状态和回调函数的剥离,并且分离之后能够还能使回调函数正常执行

    2.如何实现链式调用并且管理状态

    首先是构造函数:

    //全局宏定义
    var PENDING = 0;
    var FULFILLED = 1;
    var REJECTED = 2;
    //Promise构造函数
    function Promise(fn){
        var self = this;
        self.state = PENDING;//初始化状态
        self.value = null;//存储异步结果的对象变量
        self.handlers = [];//存储回调函数,这里没保存失败回调函数,因为这是一个dome
        //异步任务成功后处理,这不是回调函数
        function fulfill(result){
            if(self.state === PENDING){
                self.state = FULFILLED;
                self.value = result;
                for(var i=0;i<self.handlers.length;i++){
                    self.handlers[i](result);
                }
                
            }
        }
    
        //异步任务失败后的处理,
        function reject(err){
            if(self.state === PENDING){
                self.state = REJECTED;
                self.value = err;
            }
        }   
        fn&&fn(fulfill,reject);
    
    };

    构造函数接受一个异步函数,并且执行这个异步函数,修改promise对象的状态和结果。

    回调函数方法then:

    //使用then方法添加回调函数,把这次回调函数return的结果当做return的promise的resolve的参数
    Promise.prototype.then = function(onResolved, onRejected){
        var self = this;
        return new Promise(function(resolve, reject){
            var onResolvedFade = function(val){
                var ret = onResolved?onResolved(val):val;//这一步主要是then方法中传入的成功回调函数通过return来进行链式传递结果参数
                if(ret instanceof Promise){//回调函数返回值也是promise的时候
                    ret.then(function(val){
                        resolve(val);
                    });
                }
                else{
                    resolve(ret);
                }
            };
            var onRejectedFade = function(val){
                var ret = onRejected?onRejected(val):val;
                reject(ret);
            };
            self.handlers.push(onResolvedFade);
            if(self._status === FULFILLED){
                onResolvedFade(self._value);
            }
    
            if(self._status === REJECTED){
                onRejectedFade(self._value);
            }
        });
    }

    通过上面的代码可以看出,前面提出的2个问题得到了解决,1.在promise对象中有3个属性,state,value,handlers,这3个属性解决了状态和回调的脱离,并且在调用then方法的时候才将回调函数push到handlers属性上面(此时state就是1,可以在后面的代码中执行onResolve)2.链式调用通过在then方法中返回的promise对象实现,并且通过onResolvedFade将上一个回调的返回值当做这次的result参数来执行进行传递。

    测试代码:

    function async(value){
        var pms = new Promise(function(resolve, reject){
            setTimeout(function(){
                resolve(value);;
            }, 1000);
        });
        return pms;
    }
    async(1).then(function(result){
        console.log('the result is ',result);//the result is 2 
        return result;
    }).then(function(result){
        console.log(++result);//2
    });

     

  • 相关阅读:
    【NOIP2007】守望者的逃离
    20200321(ABC)题解 by 马鸿儒 孙晨曦
    20200320(ABC)题解 by 王一帆
    20200319(ABC)题解 by 王一帆 梁延杰 丁智辰
    20200314(ABC)题解 by 董国梁 蒋丽君 章思航
    20200309(ABC)题解 by 梁延杰
    20200307(DEF)题解 by 孙晨曦
    20200306(ABC)题解 by 孙晨曦
    20200305(DEF)题解 by 孙晨曦
    20200303(ABC)题解 by 王锐,董国梁
  • 原文地址:https://www.cnblogs.com/zhansu/p/6530844.html
Copyright © 2011-2022 走看看