对Promise的理解,主要是对Promise源代码分析展开(附上github链接https://github.com/then/promise):
Promise 对象是一个代理对象(代理一个值),被代理的值在Promise对象创建时可能是未知的。它允许你为异步操作的成功和失败分别绑定相应的处理方法(handlers)。 这让异步方法可以像同步方法那样返回值,但并不是立即返回最终执行结果,而是一个能代表未来出现的结果的Promise对象。
先来看个简单例子:
var pro = new Promise(function(res,rej){
setTimeout(function(){
console.log('1s execute...');
res(1)
},1000)
})
.then(function(n){
console.log(n)
})
从上面例子可以看出,promise接受一个函数,这个函数接受2个参数,分别负责来实现异步行为之后的回调操作。
接下来,我们来看看源代码:
function Promise(fn) {
if (typeof this !== 'object') {
throw new TypeError('Promises must be constructed via new');
}
if (typeof fn !== 'function') {
throw new TypeError('Promise constructor\'s argument is not a function');
}
this._deferredState = 0;
this._state = 0;
this._value = null;
this._deferreds = null;
if (fn === noop) return;
doResolve(fn, this);
}
上面这部分代码其实就是接受函数,并执行promise里面传的参数,重点在doResolve这个方法,看这个方法之前先看3个基本的工具方法:
// 获取某个对象的then属性
function getThen(obj) {
try {
return obj.then;
} catch (ex) {
LAST_ERROR = ex;
return IS_ERROR;
}
}
// 执行调用fn,并传入一个参数
function tryCallOne(fn, a) {
try {
return fn(a);
} catch (ex) {
LAST_ERROR = ex;
return IS_ERROR;
}
}
// 执行调用fn,并传入两个参数
function tryCallTwo(fn, a, b) {
try {
fn(a, b);
} catch (ex) {
LAST_ERROR = ex;
return IS_ERROR;
}
}
这时候,再来看一下doResolve这个方法:
function doResolve(fn, promise) {
var done = false;
var res = tryCallTwo(fn, function (value) {
if (done) return;
done = true;
resolve(promise, value);// 将当前promise和resolve 的value传进去
}, function (reason) {
if (done) return;
done = true;
reject(promise, reason);
});
if (!done && res === IS_ERROR) {
done = true;
reject(promise, LAST_ERROR);
}
}
这个方法主要就是执行了新建promise对象时候传的函数,我们仔细看第2、3个参数,这2个函数执行的时候,会分别进入resolve和reject方法里面,我们以resolve为例,来看看内部的resolve干了什么:
function resolve(self, newValue) {
// Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
if (newValue === self) {
return reject(
self,
new TypeError('A promise cannot be resolved with itself.')
);
}
if (
newValue &&
(typeof newValue === 'object' || typeof newValue === 'function')
) {
var then = getThen(newValue);
if (then === IS_ERROR) {
return reject(self, LAST_ERROR);
}
if (
then === self.then &&
newValue instanceof Promise
) {
self._state = 3; // 如果value本身是一个promise对象,则状态跟着这个promise走
self._value = newValue;
finale(self);
return;
} else if (typeof then === 'function') { // 如果value是一个带then函数的对象,则继续走doResolve(基于then函数)
doResolve(then.bind(newValue), self);
return;
}
}
// 如果value没啥特殊的,就走正常程序
self._state = 1; // state变为1
self._value = newValue;
finale(self);
}
我们顺着最简单的情况看流程哈,因为任何特殊情况,走到最后都是最简单的情况。这样,接着看finale函数:
function finale(self) {
// 简单意思便是:一个一个执行promise对象队列中的deferreds
if (self._deferredState === 1) {
handle(self, self._deferreds);
self._deferreds = null;
}
if (self._deferredState === 2) {
for (var i = 0; i < self._deferreds.length; i++) {
handle(self, self._deferreds[i]);
}
self._deferreds = null;
}
}
怎么突然冒出来个_deferreds来了呢,其实_deferreds可以理解为当前异步执行队列中的处理器,那么它的赋值是在哪里做的呢?我们来看下promise的then方法的代码:
Promise.prototype.then = function(onFulfilled, onRejected) {
if (this.constructor !== Promise) {
return safeThen(this, onFulfilled, onRejected);
}
var res = new Promise(noop); // then方法,新建一个promise
handle(this, new Handler(onFulfilled, onRejected, res)); // 并将新建一个handler,然后再进行处理
return res;
};
function safeThen(self, onFulfilled, onRejected) {
return new self.constructor(function (resolve, reject) {
var res = new Promise(noop);
res.then(resolve, reject);
handle(self, new Handler(onFulfilled, onRejected, res));
});
}
我们先来看下Handler构造函数干了啥:
function Handler(onFulfilled, onRejected, promise){
this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
this.onRejected = typeof onRejected === 'function' ? onRejected : null;
this.promise = promise;
// 新建了一个对象,promise属性存储当前传进来的promise对象,onfulfilled/onRejected分别存储then方法传进来的回调函数
}
这样,结合上面,我们可以发现then的时候,将对应的handler放到了handle方法中去处理,我们看看handle方法:
function handle(self, deferred) {
while (self._state === 3) {
// 当state为3的时候,则整个状态依赖于新的那个promise类型的value
self = self._value;
}
if (Promise._onHandle) {
Promise._onHandle(self);
}
if (self._state === 0) {// 当还是0的时候,往_deferreds里面放处理器(也就是then方法执行的逻辑点)
if (self._deferredState === 0) {
self._deferredState = 1;
self._deferreds = deferred;
return;
}
if (self._deferredState === 1) {
self._deferredState = 2;
self._deferreds = [self._deferreds, deferred];
return;
}
self._deferreds.push(deferred);
return;
}
// 如果state为1或者2,直接进入handleResolved
handleResolved(self, deferred);
}
来看看handleResolved源代码:
function handleResolved(self, deferred) {
asap(function() {
var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected;// 根据状态来选择调取的回调函数
if (cb === null) {
if (self._state === 1) {
resolve(deferred.promise, self._value);
} else {
reject(deferred.promise, self._value);
}
return;
}
var ret = tryCallOne(cb, self._value); // 将值传人回调函数,并返回执行结果
if (ret === IS_ERROR) {
reject(deferred.promise, LAST_ERROR);
} else {
resolve(deferred.promise, ret); // 再将当前结果resolve运行到then返回的promise中去
}
});
}
到此为止,咱们已经把promise的主要核心代码已经分析过一遍了。仔细想想,其实主要就围绕着以下几个关键点展开:
1、执行传到promise构造函数的函数;
2、根据then和handle方法结合,将需要处理的handlers放在处理队列之中;
3、内部实现的resolve和reject方法分别更新当前promise对象的状态;
4、根据状态来执行对应的处理函数;
5、循环上述过程。
下面看几个实际例子来配合理解:
=========================
// 例子1:简单传值
var pro = new Promise(function(res,rej){
setTimeout(function(){
console.log('1s execute...')
res(1)
},1000)
});
pro.then(function(n){
console.log(n)
})
// 例子1输出结果:
1s execute...
1
=========================
// 例子2: 连续传递,且第1个then方法不返回值
var pro = new Promise(function(res,rej){
setTimeout(function(){
console.log('1s execute...')
res(1)
},1000)
});
pro.then(function(n){
console.log(n)
}).then(function(m){
console.log(m)
})
// 例子2输出结果:
1s execute...
1
undefined
=========================
// 例子3:连续传递,且第1个then方法正常返回值
var pro = new Promise(function(res,rej){
setTimeout(function(){
console.log('1s execute...')
res(1)
},1000)
});
pro.then(function(n){
console.log(n);
return 2;
}).then(function(m){
console.log(m)
})
// 例子3输出结果:
1s execute...
1
2
=========================
// 例子4:连续传递,且第1个then方法返回promise,但是不res更改状态,会中断传递
var pro = new Promise(function(res,rej){
setTimeout(function(){
console.log('1s execute...')
res(1)
},1000)
});
pro.then(function(n){
console.log(n);
return new Promise(function(res,rej){
setTimeout(function(){
console.log('promise waiting')
},1000)
})
}).then(function(m){
console.log(m)
})
// 例子4输出结果:
1s execute...
1
promise waiting
=========================
// 例子5:连续传递,且第1个then方法返回promise,但是不res更改状态,不会中断传递
var pro = new Promise(function(res,rej){
setTimeout(function(){
console.log('1s execute...')
res(1)
},1000)
});
pro.then(function(n){
console.log(n);
return new Promise(function(res,rej){
setTimeout(function(){
console.log('promise waiting');
res('promise 传递');
},1000)
})
}).then(function(m){
console.log(m)
})
// 例子5输出结果:
1s execute...
1
promise waiting
promise 传递
网友评论