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);
}
调用promise
// 实例化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.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。
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);
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。