function Promise(fn){ //须要一个成功时的回调 var self = this var callback; //一个实例的方法,用来注册异步事件 self.then = function(done){ callback = done; } // resolve 比 then 先执行 此时 callback 不存在 // 因此 加一个 setTimeout 让resolve 函数在回调队列的末尾 // 为啥是0秒? 为啥处于回调队列末尾? //(权威指南)若是以0毫秒的超时时间来调用setTimeout(),那么指定的函数不会当即执 // 行,相反会把它放到队列中去,等到前面处于等待状态的事件处理程序所有执行完成后, // 再“当即”调用它。 // 如下 方式写 提示 resolve 未定义 涉及闭包 做用域链的问题 // setTimeout(function () { // function resolve(value){ // callback && callback(value); // } // }, 0) // 改进方式 function resolve (value) { setTimeout(function () { callback && callback(value) }, 0) } fn(resolve); }
调用promisehtml
// 实例化promise 回调函数fn执行成功,并执行resolve函数,此时在回调队列里面添加一 // 一个callback函数,并将resolve的参数传递出去。 var promise = new Promise(function (resolve) { resolve(['3', 'aaa']) }) // 调用then函数,并执行then回调,将then函数的参数done回调函数赋值给callback, // 在回调队列里面(以前setTimeout添加进去的回调队列)执行then的回调函数 promise.then(function (data) { console.log('data', data) })
可是以上方式写,咱们永远都只能执行then中一个回调队列,这显然不健壮。咱们结合js设计模式的发布--消息订阅模式,再结合构造函数return this 知识点,稍微改造下:设计模式
function Promise(fn){ //须要一个成功时的回调 var self = this self.deferreds = []; // then函数 回调队列 储存容器 //一个实例的方法,用来注册异步事件 self.then = function(onFulfilled){ self.deferreds.push(onFulfilled) console.log('self.deferreds', self.deferreds) // 调用两次then 回调队列会逐个push return self // 链式调用then } // 改进方式 function resolve (value) { setTimeout(function () { self.deferreds.forEach(function (deferred) { deferred && deferred(value) }) }, 0) } fn(resolve); }
调用then函数:promise
promise.then(function (data) { console.log('data', data) }).then(function (resp) { console.log('resp', resp) })
众所周知,构造函数Promise存在三个互斥状态:pending、fulfilled、rejected。Promise 对象的状态改变,只有两种可能:从 pending 变为 fulfilled 和从 pending 变为 rejected。只要这两种状况发生,状态就凝固了,不会再变了,会一直保持这个结果。闭包
因此:咱们改进代码以下:异步
//略 // 初始化设置状态 self.status = 'pending' //略 // ... //略 // resolve的时候 将状态置为 self.status = 'fulfilled' //略
调用执行,一样能够获得咱们想要的数据。
可是
可是
可是
仅仅加上上面两行代码是不行的,仔细理解加粗的那几个字,再结合咱们的代码来看。
当咱们调用then函数的时候,往咱们then回调队列里面push回调函数,最终无论状态是pending
仍是fulfilled,回调队列的函数都是被resolve函数触发的。这样就违背了这句话:只要这两种状况发生,状态就凝固了,不会再变了,会一直保持这个结果。
当咱们状态改变为fulfilled,咱们并无真正改变状态,每次再从新执行的时候,咱们又从新走了一次then添加回调,而后由resolve来触发回调的过程。
因此then函数改进代码以下:函数
// 当status == 'pending'的时候,咱们才往then的回调队列push回调函数。 // 不然 直接执行回调函数,不会由resolve来触发then的回调函数执行。 if(self.status == 'pending') { self.deferreds.push(onFulfilled) return self } onFulfilled(value) return self // 链式调用then
因此加入value后,最终代码以下:
基本就实现了链式调用then的一个带有pending 和 fulfilled 状态的Promise
后续会加上reject(), rejected以及最难理解的串行promise。this
function Promise(fn){ //须要一个成功时的回调 var self = this self.deferreds = []; // then函数 回调队列 储存容器 self.status = 'pending' self.value = null //一个实例的方法,用来注册异步事件 self.then = function(onFulfilled){ if(self.status == 'pending') { self.deferreds.push(onFulfilled) return self } onFulfilled(self.value) return self // 链式调用then } // 改进方式 function resolve (newValue) { setTimeout(function () { self.value = newValue self.status = 'fulfilled' self.deferreds.forEach(function (deferred) { deferred && deferred(self.value) }) }, 0) } fn(resolve); }