你能不能总是在 promise 上使用 .then/.catch,如果它已经完成,它会从它到达的地方继续,所以它在概念上看起来像一个大链,会在某些时候运行到完成不确定点?
是的,你总是可以在 promise 上使用 .then/.catch。当你拨打p.then()时,有三种可能。
promise p 仍处于待处理状态(尚未完成或拒绝)。如果是这种情况,那么您传递给 .then() 的函数引用将注册为该承诺的侦听器。因此,当未来的状态转换发生在 Promise 上时(从挂起 => 已完成或从挂起 => 拒绝),将调用适当的注册监听器。
承诺p 已经实现。如果是这种情况,那么调用.then(f1, f2) 将安排f1 在下一个滴答声中被调用(在当前一段Javascript 完成执行之后),并将传递保存的解析值。
promise p 已被拒绝。如果是这种情况,那么调用.then(f1, f2) 将安排f2 在下一次滴答时被调用(在当前的Javascript 完成执行后),它将传递保存的拒绝原因。
因此,在已经履行或拒绝的承诺上调用 .then() 是完全安全的。适当的侦听器将被安排在下一个滴答时运行。
同样的逻辑也适用于.catch(),只是它只对上述情况 1 和 3 感兴趣。
这里是
如果是这样,那是不是意味着每次你创建一个 Promise 链时它都会一直挂着?
Promise 只是对象,就像 Javascript 中的任何其他对象一样。只有当其他代码仍然对它们有一些实时引用时,它们才会徘徊。一旦不再有任何方法可以访问该 promise 对象,它们就会像 Javascript 中的任何其他对象一样有资格进行垃圾回收。
所以,如果你这样做:
var p = somePromiseReturningFunction();
p.then(f1).then(f2).then(f3);
然后,p 将一直存在,直到 somePromiseReturningFunction() 完成对它返回的承诺的任何引用(通常,尽管并不总是,这发生在承诺最终被履行或拒绝时)以及当变量 @987654337 @ 超出范围。如果p 永远不会超出范围(例如当它是全局的或在其他持久范围内时),那么它将永远存在(就像任何其他 Javascript 对象一样)。
你的问题有一些误解,所以让我试着纠正一下。
您使用的构造 p = p.then(dosomething(x)); 可能不正确。您需要传递.then() 一个函数引用。因此,除非您希望 doSomething(x) 立即执行并且它还返回另一个您想要调用的函数,然后是 .then() 处理程序(这在此处似乎不太可能),否则这不是正确的构造。你可能本来打算:
p = p.then(result => dosomething(x));
或者在 ES5 语法中:
p = p.then(function(result) {
return dosomething(x)
});
你也显示了同样的问题:
return p.then(finalthing()).catch(pretendnobadthing());
应该是:
return p.then(finalthing).catch(pretendnobadthing);
请记住,当您使用f() 时,这意味着立即执行f。当您只传递f 时,它会传递一个函数引用,您传递给它的底层函数/方法可以在稍后选择它时调用,这就是您想要的.then() 和.catch() 处理程序。
我真正不明白的是,如果您在主代码中做一些需要大量时间的事情,这是否意味着其中一个承诺可以在主代码实际开始设置之前完成.then.
首先,我在回答开头的原始解释应该解释说,在已经解决的承诺上调用 .then() 非常好,所以这根本不是问题。它只会在事件循环的下一个滴答声中安排动作。
但是,这里甚至不是这种情况,因为浏览器和 node.js 中的 Javascript 是单线程的,所以当您的长时间运行的代码正在运行时,该承诺(之前启动了谁的异步操作)还不能得到解决。虽然底层的异步操作可能已经完成,并且一个事件可能位于 Javascript 事件队列中,该事件将触发一个回调来解决 Promise,但事件队列中的该事件直到当前正在执行的 Javascript 片段才会得到处理完成并将控制权返回给系统。