[ECMAScript] Promise相关的几个术语
1. fulfilled,rejected,pending
A Promise is an object that is used as a placeholder for the eventual results of a deferred (and possibly asynchronous) computation.
Any Promise object is in one of three mutually exclusive states: fulfilled, rejected, and pending:
A promise p is fulfilled if
p.then(f, r)
will immediately enqueue a Job to call the functionf
.
A promise p is rejected ifp.then(f, r)
will immediately enqueue a Job to call the function r.
A promise is pending if it is neither fulfilled nor rejected.
一个promise总共有三种状态,pending,fulfilled/rejected,new Promise
构造函数创建的promise,初始处于pending状态。
pending的时候不向Job Queue加入任何Job。
当一个promise p
被fulfilled/rejected的时候,会立即向名字为PromiseJobs
的Job Queue加入一个Job,这个Job做的事情就是调用p.then(f, r)
中的f
/r
。
2. settled,resolved
A promise is said to be settled if it is not pending, i.e. if it is either fulfilled or rejected.
A promise is resolved if it is settled or if it has been “locked in” to match the state of another promise. Attempting to resolve or reject a resolved promise has no effect. A promise is unresolved if it is not resolved. An unresolved promise is always in the pending state. A resolved promise may be pending, fulfilled or rejected.
2.1 settled
一个promise被settled,指的是它脱离了pending状态,或者被fulfilled或者被rejected。
2.2 resolved
resolve/reject一个promise,
指的是调用new Promise((res,rej)=>{...})
中的res
/rej
函数。
调用了res
函数之后的promise,称为resolved。
2.3 如何理解“locked in”
A promise is resolved if it is settled or if it has been “locked in” to match the state of another promise.
要想理解“locked in”,首先要知道,res
函数可以接受三种类型的值作为参数,
或者是一个promise,或者是一个带有then
方法的对象,或者是其他值。
这里“locked in”指的是res
接受promise,或者接受带有then
方法对象的情况,
这种方式进行resolve,会使得当前的promise仍然处于pending状态,
其settled结果,与其参数对象的最终状态有关。
例子:
(1)res
的参数为promise的例子,
a = new Promise((res,rej)=>setTimeout(()=>res(1),1000));
b = new Promise((res,rej)=>res(a));
b.then(v=>console.log(v));
(2)res
的参数为带then
方法的对象的例子,
a = {
then:(res,rej)=>setTimeout(()=>res(1),1000)
};
b = new Promise((res,rej)=>res(a));
b.then(v=>console.log(v));
2.4 多次resolve无效
Attempting to resolve or reject a resolved promise has no effect.
一个promise一旦resolved,再次resolve/reject将失效。
无论第一次resolve所使用的参数是什么,
例如,即使第一调用res
仍然使promise处于pending状态。
a = new Promise((res,rej)=>{
res({
then:(res,rej)=>setTimeout(()=>res(1),1000)
});
res(2);
setTimeout(()=>rej(3),1000);
});
a.then(
v => console.log(v),
e => console.warn(e)
);
3. Enqueue Job
3.1 何时p.then(f, r)会Enqueue Job
如果promise p
还没有被settled,那么p.then(f, r)
,会将f
/r
放入promise的[[PromiseFulfillReactions]]
/[[PromiseRejectReactions]]
列表尾部。
如果p
已经被settled,会向名为PromiseJobs
的Job Queue中添加一个用来处理fulfilled/rejected的PromiseReactionJob。
因此,一个已经settled的promise,每次调用p.then(f, r)
会Enqueue Job。[[PromiseFulfillReactions]]
和[[PromiseRejectReactions]]
的作用是,当promise处于pending状态时,保存p.then(f, r)
所添加的处理器函数f
和r
。
3.2 使用res / rej Enqueue的两种Job
res
会出现在以下两个地方:
(1)带有then
方法的对象中,{then:(res,rej)=>{...}}
用一个带有then
方法的对象调用res
,会向名为PromiseJobs
的Job Queue中添加一个PromiseResolveThenableJob。
(2)new Promise((res,rej)=>{...})
构造函数中
调用res
/rej
,会导致promise被settled,(只能被settle一次)
此时会清空promise的[[PromiseFulfillReactions]]
和[[PromiseRejectReactions]]
列表,并向名为PromiseJobs
的Job Queue中添加一个用来处理fulfilled/rejected的 PromiseReactionJob。
因此,调用res
/rej
总是会Enqueue Job。
当promise被settled的时候,[[PromiseFulfillReactions]]
和[[PromiseRejectReactions]]
就没有用了,因为settled状态的promise,即使再添加处理器p.then(f, r)
,也是直接Enqueue Job,和[[PromiseFulfillReactions]]
和[[PromiseRejectReactions]]
无关。
a = new Promise(res=>setTimeout(()=>res(1),1000));
a.then(v=>console.log(v));
setTimeout(()=>a.then(v=>console.warn(v)),2000);
参考
*: What is the correct terminology for javascript promises
ECMAScript 2018 Language Specification