准备从最基础的promise慢慢讲上去
基础版
function Promise(fn) {
var value = null,
callbacks = []; //callbacks为数组,因为可能同时有很多个回调
this.then = function (onFulfilled) {
callbacks.push(onFulfilled);
//因为要链式调用then(),
return this;
};
function resolve(value) {
callbacks.forEach(function (callback) {
callback(value);
});
}
fn(resolve);
}
先分析上面的代码,new Promise()之后,fn(resolve)函数就先执行了,fn是一个耗时的异步操作。但是我想让fn执行完之后,再执行resolve函数,我该怎么办?我们可以看到有个then方法,then是向队列里面加函数的,resolve是循环执行对列里面的函数的。说到这里,大概就知道异步操作是怎么搞的了。就是先fn->通过then加回调函数到队列->最后执行resolve,把队列里面的函数拿出来去变遍历执行。
有个问题,假如resolve执行完了之后,再注册的then,then就不能执行了,所以我们改一版
resolve在then之后执行的版本
function Promise(fn) {
var value = null,
callbacks = []; //callbacks为数组,因为可能同时有很多个回调
this.then = function (onFulfilled) {
callbacks.push(onFulfilled);
};
function resolve(value) {
setTimeout(function() {
callbacks.forEach(function (callback) {
callback(value);
});
}, 0)
}
fn(resolve);
}
这里用到了setTimeout(fn,0)的技巧,把resolve放在队列的最后去执行,这样就实现了then->resolve这样的流程了。
状态改变不可变更版本
我们都知道,promise 实例有3个状态,如下图,从pending到fulfilled和rejected都是不可逆的。
我们就加入状态吧
function Promise(fn) {
var state = 'pending',
value = null,
callbacks = [];
this.then = function (onFulfilled) {
if (state === 'pending') {
callbacks.push(onFulfilled);
return this;
}
return this;
};
function resolve(newValue) {
value = newValue;
state = 'fulfilled';
setTimeout(function () {
callbacks.forEach(function (callback) {
callback(value);
});
}, 0);
}
fn(resolve);
}
上述代码的思路是这样的:resolve执行时,会将状态设置为fulfilled,之后添加的then就不执行了。
总结
上面能实现一个基本的Promise,只是为了讲原理,其实就是闭包+函数回调+单线程这些的组合,搞出一个异步解决方案。当然还有失败处理啊,异常处理啊这些东西,原理都差不多。