探究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
});

 

原文地址:https://www.cnblogs.com/zhansu/p/6530844.html