4道经典Promises执行顺序谜题的详细执行逻辑求解
前提说明
- 代码中
doSomething()、doSomethingElse均为返回Promise对象的函数 finalHandler为后续回调处理函数
谜题1
doSomething().then(function () { return doSomethingElse(); }).then(finalHandler);
首先执行doSomething(),等它返回的Promise状态变为resolved后,触发第一个then的回调函数。回调里显式return doSomethingElse(),所以这个then返回的Promise会等待doSomethingElse()的Promise执行完成,才会触发下一个then的finalHandler。执行顺序为串行:doSomething()执行完成 → doSomethingElse()执行完成 → finalHandler执行。
谜题2
doSomething().then(function () { doSomethingElse(); }).then(finalHandler);
doSomething()完成后触发第一个then的回调,回调里执行了doSomethingElse(),但是没有return它的Promise。这时候then会默认返回一个状态为resolved的空Promise,不会等待doSomethingElse()的执行结果,所以紧接着就会触发下一个then的finalHandler。这就导致doSomethingElse和finalHandler几乎同时启动、同时结束,二者并行执行没有依赖关系。
谜题3
doSomething().then(doSomethingElse()) .then(finalHandler);
问题出在then(doSomethingElse())的写法:你给then传的不是函数引用,是直接调用了doSomethingElse()。JS代码是从上到下同步解析执行的,所以在解析到这一行的时候,doSomething()和doSomethingElse()会被先后立刻执行,根本不会等doSomething()的Promise完成。这时候then接收到的是doSomethingElse()返回的Promise对象,不属于合法的回调函数入参,then会直接忽略该入参,把上一层doSomething()的结果往下透传,等doSomething()完成后就直接触发finalHandler,所以doSomething和doSomethingElse会同时启动。
谜题4
doSomething().then(doSomethingElse) .then(finalHandler);
这里给then传的是doSomethingElse的函数引用,不是调用结果。doSomething()执行完成后,会把自己的resolve值作为参数传给doSomethingElse,触发doSomethingElse执行,并且then会自动等待doSomethingElse返回的Promise状态变为resolved,再触发后续的finalHandler。执行顺序和谜题1完全一致,只是把匿名函数包装的写法简化为直接传函数引用,属于更简洁的常规写法。
内容的提问来源于stack exchange,提问作者miouri

