参考自:https://segmentfault.com/a/1190000012500519?from=timeline
1. 最简单的一个案例
function runAsync() {
let p = new Promise(function(resolve, reject) {
console.log('exec');
setTimeout(function() {
reslove('someData');
}, 2000);
});
return p;
}
var promise = runAsync();
promise.then(function(data) {
console.log(data);
});
console.log('同步执行');
console.log(promise);
2. Promise内部是如何运行的?
2.1 执行这行代码的时候:let p = new Promise(f);
function noop() {};
function Promise(fn) {
if (typeof this !== 'object') {
throw new TypeError('Promise must be consructed via new');
}
if (typeof fn !== 'function') {
throw new TypeError('Promise consructor's argument is not a function);
}
this._deferredState = 0;
this._state = 0;
this._value = null;
this._deferreds = null;
// 注意这里,如果fn传入的是noop这个函数,那么不会执行doResolve
if(fn === noop) return;
doResolve(fn, this);
}
Promise._onHandle = null;
Promise._onReject = null;
Promise._noop = noop;
function doResolve(fn, promise) {
var done = false;
var res = tryCallTwo(fn, function(value) {
if (done) return;
done = true;
resolve(promise, value);
}, function(reason) {
if (done) return;
done = true;
reject(promise, LAST_ERROR);
});
}
function tryCallTwo(fn, a, b) {
try {
fn(a, b);
} catch (ex) {
LAST_ERROR = ex;
return IS_ERROR;
}
}
可以看到let p = new Promise(f); 在传入的f函数不是noop的时候:
- 第一会先执行f函数
- 第二生成一个Promise对象
p => {
_deferredState : 0, // deffer的状态,代表的应该是_deferreds的类型:1代表single,2代表Array
_state : 0, // 每个promise对象的状态维护标识
_value : null, // resolve函数执行的时候,异步得到的结果
_deferreds : null
}
2.2 执行这行代码的时候:promise.then(function(data){console.log(data);});
Promise.prototype.then = function(onFulfilled, onRejected) {
if (this.constructor !== Promise) { // 这些比较的都是引用地址;
return safeThen(this, onFulfilled, onRejected);
}
var res = new Promise(noop);
handle(this, new Handler(onFulfilled, onRejected, res));
// 注意这里then的链式调用,每次then函数执行完毕之后,返回值都是一个新的Promise实例对象
return res;
};
// 这里生成一个deferred对象,保存then函数中注册的onFulfilled和onRejected回调,以及要返回的新的promise实例对象
function Handler(onFulfilled, onRejected, promise) {
this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
this.onRejected = typeof onRejected === 'function' ? onRejected : null;
this.promise = promise;
}
function handle(self, deferred) {
// 不会进入这里
while (self._state === 3) {
self = self._value;
}
// 也不会进入这里
if (Promise._onHandle) {
Promise._onHandle(self);
}
// 进入这里,注意这里,如果通过then的链式调用,那么每次then返回的对象都是一个新的类似于下面p的实例对象
if (self._state === 0) {
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(self, deferred);
}
此时再来看下p这个promise实例的属性值
p => {
_.deferredState: 1, // deferreds的状态
_.state: 0, // 每个promise对象的状态维护标识
_.value: null, // resolve函数执行的时候,异步得到的结果
_.deferreds: new Handler(onFulfilled, onRejected, res); // 存放通过then注册的函数以及返回Promise实例对象的一个Handler对象
}
res: {
_deferredState: 0, // deferreds的状态
_state: 0, // 每个promise对象的状态维护标识
_value: null, // resolve函数执行的时候,异步得到的结果
_deferreds: null
}
如果返回的res在执行then方法,那么
p => {
_.deferredState: 1, // deferreds的状态
_.state: 0, // 每个promise对象的状态维护标识
_.value: null, // resolve函数执行的时候,异步得到的结果
_.deferreds: new Handler(onFulfilled, onRejected, res); // 存放通过then注册的函数以及返回Promise实例对象的一个Handler对象
}
res: {
_deferredState: 1, // deferreds的状态
_state: 0, // 每个promise对象的状态维护标识
_value: null, // resolve函数执行的时候,异步得到的结果
_deferreds: new Handler(onFulfilled, onRejected, res); // 存放通过then注册的函数以及返回的Promis实例对象的一个Handler对象
}
2.3 异步操作完成以后:resolve('someData');
// 真正调用这个函数的是tryCallTwo中的第二个函数入参数。
// self就是p这个promise实例对象。
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 (
// 比如resolve(p1),p1是一个新的promise对象
newValue &&
(typeof newValue === 'object' || typepf 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;
self._value = newsValue;
finale(self);
return;
} else if (typeof then === 'function') {
doResolve(then.bind(newValue), self);
return;
}
}
// 对于简单的返回值,比如后台返回的JSON字符串等,这里就直接进行处理
self._state = 1; // fulfilled
self._value = newsValue; // 给这个promise对象添加属性值_value,用来保存异步操作的结果
finale(self); // 最后处理这个promise对象
}
此时的promise实例对象,关注对比p这个实例对象的变化,可以看到resolve之后,相当于将异步的结果给到了p这个Promise实例对象的_value属性值,同时改变这个p的状态_state为1 ==> fulfilled
p => {
_deferredState: 1, // deferred的状态
_state: 1, // 每个promise对象的状态维护标识
_value: 'someDate', // resolve函数执行的时候,异步得到的结果
_deferreds: new Handler(onFulfilled, onRejected, res);
}
2.4 finale(self); // 最后处理这个promise对象
function finale(self) {
// 进入这个if语句
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;
}
}
function handle(self, deferred) {
while (self._state === 3) {
self = self._value;
}
if(Promise._onHandle) {
Promise._onHandle(self);
}
// 此时不会进入这里因为_state的值为 1
if (self._state === 0) {
if (self._deferredSate === 0) {
self._deferredSate = 1;
self._deferreds = deferred;
return;
}
if (self._deferredSate === 1) {
self._deferredSate = 2;
self._deferreds = [self._deferreds, deferred]];
return;
}
self._deferreds.push(deferred);
return;
}
// 这个函数只有当_state的值为
// 1即:fulfilled.
// 2即:rejected.
// 的时候才执行
handleResolved(self, deferred);
}
function handleResolved(self, deferred) {
asap(function() {
// 得到promise.then(function(data){console.log(data);}); 注册的函数
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;
}
// 执行then中注册的回调函数
var ret = tryCallOne(cb, self._value);
if (ret === IS_ERROR) {
reject(deferred.promise, LAST_ERROR);
} else {
resolve(deferred.promise, ret);
}
});
};
function tryCallOne(fn, a) {
try {
return fn(a);
} catch (ex) {
LAST_ERROR = ex;
return IS_ERROR;
}
}
至此一个简单的promise的实现流程完毕:
以下面实例来看一下:
3 对于then的链式调用,Promise内部又是如何运行的呢?
下一个then中注册的函数会接收到上一个then的返回值作为该then中注册的函数的参数;
3.1 then注册的函数返回基本数据类型
function runAsync() {
let p = new Promise(function(resolve, reject) {
console.log('exec');
setTimeout(function() {
resolve('someData');
}, 2000);
});
return p;
}
var promise = runAsync();
promise.then(function(data) {
console.log(data);
return 'someData1';
}).then(function(data) {
console.log(data);
return 'someData2';
}).then(function(data) {
console.log(data);
});
console.log('同步执行');
console.log(promise);
控制台输出:
exec
同步执行
Promise
// 两秒后
someData
someData1
someData2
resolve(deferred.promise, ret);中的ret值就是then中注册函数的返回值,这里就是一些简单的字符串'someData1''someData2'
promise实例对象==> 异步成功 ==> 该实例对象的resolve(data) ==>
//newValue为异步得到的数据,第一次是'someData'这个字符串,下一次就是then中注册函数的返回值ret,还是字符串'someData1' 'someData2'
resolve(self,newValue) ==> <== == == == == == == ||
^
==>handle(self,deffer) ||
^
==>handleResolved处理then中注册的函数; ||
^
==>接着处理下一个promis==>resolve(deferred.promise, ret); ===> ||
var p = {
_deferredState: 1, // deferred的状态
_state: 0, // 每个promise对象的状态维护标识
_value: null, // resolve函数执行的时候,异步得到的结果
_deferred: {
onFulfilled: onFulfilled,
onRejected: onRejected,
promise: { // 这里使new Promise(noop)
_deferredState: 1,
_state: 0,
_value: null,
_deferreds: { // 通过then注册的执行对象
onFulfilled: onFulfilled,
onRejected: onRejected,
promise: { // 这里是:new Promise(noop)
_deferredState: 1,
_state: 0,
_value: null,
_deferreds: { // 通过then注册的执行对象
onFulfilled: onFulfilled,
onRejected: onRejected,
promise: { // 这里使new Promise(noop)
_deferredState: 1,
_state: 0,
_value: null,
_deferreds: { // 通过then注册的执行对象
onFulfilled: onFulfilled,
onRejected: onRejected,
promise: { // 这里使new Promise(noop)
_deferredState: 1,
_state: 0,
_value: null,
_deferreds: null
}
}
}
}
}
}
}
}
};
3.2 then注册的函数返回一个新的promise
function runAsync() {
let p = new Promise(function(resolve, reject) {
console.log('exec');
setTimeout(function() {
resolve('someData');
}, 2000);
});
return p;
};
function runAsync1() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve('someData1');
},2000);
});
};
function runAsync2() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve('someData2');
}, 2000);
});
};
// 以下的异步操作会按照顺序进行执行
var promise = runAsync();
promise.then(function(data) {
console.log(data);
return runAsync1();
}).then(function(data) {
console.log(data);
return runAsync2();
}).then(function(data) {
console.log(data);
// return 'someData3'
})
console.log('同步执行');
console.log(promise);
exec
同步执行
Promise
// 两秒后
someData
// 两秒后
someData1
// 两秒后
someData2
promise实例对象 ==> 异步成功 ==> 该实例对象的resolve(data) ==>
//newValue为异步得到的数据,这里第一次是 'someData'这个字符串,下一次就是then中注册函数的返回值,这里就是runAsync返回的promise对象
resolve(self,newValue) ==> <== == == == == == == ||
^
==>handle(self,deffer) ||
^
==>handleResolved处理then中注册的函数; ||
^
==>接着处理下一个promise==>resolve(deferred.promise, ret); ===> ||
整个promise链如下:
var p = {
_deferredState: 1, // deferred的状态
_state: 0, // 每个promise对象的状态维护标识
_value: null, // resolve函数执行的时候,异步得到的结果
_deferred: {
onFulfilled: onFulfilled,
onRejected: onRejected,
promise: { // 通过引用的地址改变,这里使runAsync返回的promise
_deferredState: 1,
_state: 0,
_value: null,
_deferreds: { // 由于runAsync中没有执行then注册,这里将new Promise(noop)通过then注册的对象引用拿到
onFulfilled: onFulfilled,
onRejected: onRejected,
promise: { // 通过引用的地址改变,这里是runAsync返回promise
_deferredState: 1,
_state: 0,
_value: null,
_deferreds: null
}
}
}
}
}
3.3 以上两者之间的差异性
- 相同点:每个then返回的新promise对象是一样的,都是通过then函数中定义的返回值:var res = new Promise(noop);
- 不同点:在handleResolved中,resolve(deferred.promise, ret)中的ret的值不同,ret就是每个then中注册的函数的返回值,对比以上两种情况,一个返回基本数据类型,一个返回Promise对象,接下来重点看下then中注册的函数返回promise对象的情况(注意这个和then链式调用的promise对象不是一个)
// resolve(deferred.promise, ret);
// 注意这个self,传入的是deferred这个对象中的promise这个引用地址;
// 真正调用这个函数的是tryCallTwo中的第二个函数入参;
// self就是p这个promise实例对象;
function resolve(self, newValue) {
// 此时的newValue是then中注册函数所返回的Promise实例对象
// self是deferred.promise
// 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.');
);
}
// 注意,对于then中注册的函数返回值是一个新的promise对象的时候,此时会进入这里
if (
// 比如resolve(p1) p1四一个新的promise对象;
newValue &&
(typeof newValue === 'object' || typeof newValue === 'function')
) {
var then = getThen(newValue);
if (then === IS_ERROR) {
return reject(self, LAST_ERROR);
}
if (
// 两个Promise对象原型链上都是采用的then这个函数地址
then === self.then &&
newValue instanceof promise
) {
self._state = 3;
self.value = newValue;
finale(self);
// 执行到这里,结束;
return;
} else if (typeof then === 'function') {
doResolve(then.bind(newValue), self);
return;
}
}
// 对于then中注册的函数返回一个promise对象的情况,下面就不会执行
self._state = 1;
self._value = newValue;
finale(self);
}
self ==> deferred.promise
function finale(self) {
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;
}
}
注意这里通过对promise链进行引用的改变,从而使异步的执行看起来和同步是一样的;
handle函数有两个作用:
- 第一:改变promise链的引用,将原本返回的new Promise(noop)改为ret(then)中注册函数返回的promise。
- 第二:将原本new Promise(noop)上面通过then注册的deferred对象,给到ret响应的属性。
function handle(self, deferred) {
while (self._state === 3) {
// 这里一直循环直到取到我们返回的promise对象,也就上面的ret,即每个runAsync函数的返回值;
self = self._value;
}
if (Promise._onHandle) {
Promise._onHandle(self);
}
// 将runAsync返回的promise对象中_deferredState设置为1;
if (self._state === 0) {
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;
}
handleResloved(self, deferred);
}
4. 综合练习
对于注释的代码可以来回切换,看下结果。
function runAsync() {
let p = new Promise(function(resolve, reject) {
console.log('exec');
setTimeout(function() {
resolve('someData');
}, 2000);
});
return p;
};
function runAsync1() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
console.log('异步1');
// resolve('someData1');
reject('error1');
}, 2000);
})
};
function runAsync2() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
console.log('异步2');
// resolve('someData2');
reject('error2');
}, 2000);
})
};
var promise = runAsync();
promise.then(function() {
console.log(data);
return runAsync1();
}).then(function() {
console.log(data);
return runAsync2();
}).then(function() {
console.log(data);
// return 'someData3'
}).catch(function(error) {
console.log(error);
});
console.log('同步执行');
console.log(promise);