Javascript 那么在一个JS承诺上有多条链?

Javascript 那么在一个JS承诺上有多条链?,javascript,typescript,promise,es6-promise,Javascript,Typescript,Promise,Es6 Promise,今天,我尝试了在一个承诺中添加多个then链时会发生什么。我的测试代码是这样的(TypeScript) 类测试{ 私有模拟heavystuff(时间:个){ //console.log(“-”+时间+“-”); var start=new Date().getTime(); var结束=开始; 同时(结束{ 解决(); }); //添加链1##### 承诺 .然后(()=>console.log(“then1”)) .然后(()=>this.simulateHeavyStuff(2000)) .

今天,我尝试了在一个承诺中添加多个then链时会发生什么。我的测试代码是这样的(TypeScript)

类测试{
私有模拟heavystuff(时间:个){
//console.log(“-”+时间+“-”);
var start=new Date().getTime();
var结束=开始;
同时(结束<开始+时间){
end=新日期().getTime();
}
}
测试():承诺{
让承诺=新承诺((解决、拒绝)=>{
解决();
});
//添加链1#####
承诺
.然后(()=>console.log(“then1”))
.然后(()=>this.simulateHeavyStuff(2000))
.then(()=>console.log(“then11”))
.catch(console.error)
回报承诺;
}
}
设t=新测试();
//添加链2#####
t、 测试()
.then(()=>console.log(“then2”))
.then(()=>console.log(“then21”))
.catch(console.error)
这会打印出来:

then1
then2
        <---it's pausing here
then21
then11
then1
然后2

好吧,我想我明白在评论中对Jaromanda X做了一些澄清之后会发生什么

它是完全确定的

承诺将回调添加到所谓的“微任务”堆栈中。除了其他JS堆栈,这些微任务在JS堆栈为空时运行(所有同步代码都已完成)…请参阅Jaromanda X在评论中发布的视频

所以事情是这样的:

  • “then1”被添加到MT堆栈中
  • test()返回
  • “then2”被添加到MT堆栈中
同步代码完成了!微任务时间

MT堆栈现在看起来像这样

then1
then2
然后运行1,并在返回承诺时向MT堆栈添加另一个微任务。MT堆栈现在看起来像这样

then2
heavyStuff(2000)

随着更多微任务的运行,直到MT堆栈为空,这将持续到所有MT完成。然后任何其他代码继续执行…

这是因为您的方法
test
返回
promise
变量,这与它中的
catch
返回的结果不同,因此当您调用
.test()
时,它不会等待
test
中的整个链

如果你改变

promise
    .then(()=>console.log("then1"))
    .then(()=>this.simulateHeavyStuff(2000))
    .then(()=>console.log("then11"))
    .catch(console.error)


它将如您所期望的那样工作。

答案似乎是您可能错误地创建了两个承诺(因为
。然后
在前一个承诺的基础上创建了一个新的承诺对象,请参阅)。请看下面的评论:

test(): Promise<void> {
  // this creates the base promise "A"
  let promise = new Promise((resolve, reject) => {
        resolve();
    });
  // this creates promise "A1" by adding a chain of operations to "A"
  // you are not returning it however
  promise
    .then(()=>console.log("then11"))
    .then(()=>console.log("then12"))
    .then(()=>this.simulateHeavyStuff(2000))
    .then(()=>console.log("then14"))
    .catch(console.error)

  // this returns "A" (not "A1")
    return promise;

}



// this creates promise "A2"
t.test()
  .then(()=>console.log("then2"))
  .then(()=>console.log("then21"))
  .catch(console.error)

谢谢不,我的用例可以并行添加这些回调。因此,我不需要在第一个链之后添加第二个链。我只是一开始没有得到订单背后的决定论。没有
race条件
Good point,它是单线程的。我猜第一个回调可以在离开test()方法或完成外部代码后启动?!编辑了答案:我在这里的种族条件是什么意思啊好的,所以当我添加多个链时,第一个链元素在同一个循环中被调用,第n个元素也在同一个循环中。。。?!不,我错了-好吧,没关系。。。添加到微任务队列的任务依次为1、2。。。THNE1被处理(它输出
THNE1
并将
heavystuff
添加到微任务队列中,在THNE2后面,因此会发生THNE2的console.log,它在执行heavystuff之前将
THNE21
添加到队列中…一旦heavystuff完成(这里是暂停),将
then11
添加到队列中,然后输出
then21
,然后输出
then11
。如果您想更深入地理解,这段视频做得不错谢谢!我特意创建了这两个承诺。我想要一个类来为a(创建A1)的“然后队列”和外部代码添加一些内容(调用该类的那个类)使用相同的承诺(A)它想要的方式(在创建A2的测试示例中)。关于队列,请参阅我与您的答案并行编写的关于微任务的答案,并查看视频。它很好地解释了3个堆栈(任务、动画回调、微任务)的不同排队行为。以下是正确时间的视频:“第i个链接。然后,承诺“A1”的操作将始终位于第i个链接之前。然后,承诺“A2”的操作;以及i+1链接。然后,承诺“A1”的操作必须在第i个链接之后。然后,承诺“A2”的操作。”-不,一点也不。如果A1和A2是两个独立的承诺,它们可以在任何时间以任何顺序解析。@Bergi Source?另外,请记住,我所说的是具体情况(执行步骤本身是同步的)和执行步骤,而不是整个承诺。@FK82
const logger=m=>()=>console.log(m);const delay=t=>newpromise(r=>setTimeout(r,t));const a=Promise.resolve();a.then(Math.random).then(logger(“a1”);a.then(Math.random).then(delay).then(logger(“a2”);
@FK82啊,是的,对于同步执行步骤,对于特定的Promise调度器来说可能是正确的,但您提到了“同步的”答案中没有任何地方回调是按一定顺序排队的。这是确定的,但你不需要关心顺序。如果有关系,那么将回调放在一个链中彼此之后。如果没有,并发链以各自的速度运行,并且可能交错。在任何情况下,你的问题是
simulateheavystuf
是阻塞,而不是承诺异步结果。
promise
    .then(()=>console.log("then1"))
    .then(()=>this.simulateHeavyStuff(2000))
    .then(()=>console.log("then11"))
    .catch(console.error)
promise = promise
    .then(()=>console.log("then1"))
    .then(()=>this.simulateHeavyStuff(2000))
    .then(()=>console.log("then11"))
    .catch(console.error)
test(): Promise<void> {
  // this creates the base promise "A"
  let promise = new Promise((resolve, reject) => {
        resolve();
    });
  // this creates promise "A1" by adding a chain of operations to "A"
  // you are not returning it however
  promise
    .then(()=>console.log("then11"))
    .then(()=>console.log("then12"))
    .then(()=>this.simulateHeavyStuff(2000))
    .then(()=>console.log("then14"))
    .catch(console.error)

  // this returns "A" (not "A1")
    return promise;

}



// this creates promise "A2"
t.test()
  .then(()=>console.log("then2"))
  .then(()=>console.log("then21"))
  .catch(console.error)