简体   繁体   English

将promise转换为异步等待时的时间

[英]Timing when converting promise to async await

I have the following block 我有以下块

return this
        .configure(config => {
          viewModel.configure(config, this);
          return config;
        })
        .then(() => {
          this.activate();
        });

which, is equivalent to following block, suggested by vscode auto promise->async/await conversion: 其中,相当于以下块,由vscode auto promise-> async / await转换建议:

await this.configure(config => {
  viewModel.configure(config, this);
  return config;
});
this.activate();

My question is are they actually the same in timing? 我的问题是它们在时间上实际上是一样的吗? In the promise example, shouldn't the second fn in then() 1 micro task away from the callback that accepts config ? 在promise示例中,不应该在then() 1个微任务中的第二个fn远离接受config的回调吗?

Extra question for clarity: are the following equal in timing perspective: 为清晰起见,还有一个额外的问题:时间视角如下:

Promise.all(tasks)
  .then(() => {
    othertasks.forEach(() => doStuff());
  })
  .then(() => {
    prune();
  });

and: 和:

await Promise.all(tasks);
othertasks.forEach(() => doStuff();
await Promise.resolve();
prune();

EDIT : I should clarify, with regards to Andrea Giammarchi's answer, that my answer was purely and only related to the difference in number of ticks in-between the synchronously executed code, not whether the result of that code as-written is actually equivalent (obviously, the non-awaited promises would yield promises whereas the awaited promises would yield the values) 编辑 :关于Andrea Giammarchi的回答,我应该澄清一下,我的答案纯粹而且只与同步执行代码之间的滴答数量的差异有关,而不是与编写的代码的结果是否实际等效(显然,期待已久的承诺将产生承诺,而等待的承诺将产生价值)

This would make more sense in the context that me and bigopon had a discussion in a github issue where he accepted VS Code's suggestion to remove a "redundant" .then from a promise chain in a piece of legacy code that happens to be sensitive to subtle timing issues. 这使我和bigopon在他接受VS守则的建议,删除“冗余”一个GitHub的问题进行了座谈的背景下更有意义.then从承诺链中的一条遗留代码恰好是微妙敏感时间问题。

I pointed out that this change would cause a particular method to be executed one tick earlier, and that the effects of that could potentially break complex apps relying on these (quirky) timings. 我指出,这种改变会导致一个特定的方法更早地执行一次,并且其效果可能会破坏依赖于这些(古怪)时间的复杂应用程序。

The discussion was then, whether this: 然后讨论是这样的:

somePromise.then(() => {
   ...
}).then(() => {
   doStuff();
})

Would have the same timings as this: 会有与此相同的时间:

await somePromise;
doStuff();

To which my answer was: no, the doStuff() in the second snippet would execute one tick earlier. 我的答案是:不,第二个片段中的doStuff()会先执行一个滴答。

When someone else suggested that await or .then would actually be executed synchronously if the passed-in promise was already resolved, that motivated me to write this answer and clarify why not. 如果其他人建议await.then实际上会同步执行,如果传入的承诺已经解决,那就促使我写下这个答案并澄清为什么不这样做。

I do realize that without this context, my answer can seem misleading, but again: it's just to point out the similarity in number of ticks. 我确实意识到,如果没有这种背景,我的答案似乎会产生误导,但同样重要的是:它只是指出了滴答数量的相似性。

Original answer 原始答案

Example 1 例1

For resolving a value, in plain terms, this: 为了解决价值,简单来说,这个:

await something

Is equivalent to this: 相当于:

Promise.resolve(something).then()

They both result in a pending promise. 他们都导致未决的承诺。

Example 2 例2

For queueing a task, this: 对于排队任务,这个:

await Promise.resolve();
doStuff();

Is equivalent to this: 相当于:

Promise.resolve().then(() => {
    doStuff();
})

In both cases, doStuff() happens on the next tick. 在这两种情况下, doStuff()都会在下一个tick上发生。

In order to determine whether a regular .then chain is equivalent to a series of await s, you simply need to count .then and await . 为了确定常规.then链是否等同于一系列await s,你只需要计算.thenawait If the number of each is the same between two given pieces of code, then the amount of time/ticks/whatever passing between those pieces of code will be the same. 如果两个给定代码之间的每个的数量相同,则那些代码之间的时间/滴答/任何传递的数量将是相同的。

Example 3 例3

Another example, this: 另一个例子,这个:

await Promise.resolve();
doStuff();
await Promise.resolve();
doStuff();
await Promise.resolve();
await Promise.resolve();
doStuff();

Is equivalent to this: 相当于:

Promise.resolve()
.then(() => {
    doStuff();
})
.then(() => {
    doStuff();
})
.then(() => {})
.then(() => {
    doStuff();
})

Note that the Promise.resolve() itself has no effect on the timings. 请注意, Promise.resolve()本身对时间没有影响。 It returns a resolved promise. 它返回一个已解决的承诺。 It's the then() / await that turns it into a pending one. 它是then() / await ,将其变为待定的。

So I respectfully disagree with amadan and I believe both your examples are equivalent. 所以我恭敬地不同意amadan,我相信你的例子都是等同的。

What the spec says 规范说的是什么

  1. If promise.[[PromiseState]] is "pending", then 如果承诺。[[PromiseState]]是“待定”,那么

    a. 一种。 Append fulfillReaction as the last element of the List that is promise.[[PromiseFulfillReactions]]. 将fulfillReaction追加为承诺列表的最后一个元素。[[PromiseFulfillReactions]]。

    b. Append rejectReaction as the last element of the List that is promise.[[PromiseRejectReactions]]. 将rejectReaction追加为List的最后一个承诺元素。[[PromiseRejectReactions]]。

  2. Else if promise.[[PromiseState]] is "fulfilled", then 如果承诺。[[PromiseState]]是“履行”,那么

    a. 一种。 Let value be promise.[[PromiseResult]]. 让价值成为承诺。[[PromiseResult]]。

    b. Perform EnqueueJob("PromiseJobs", PromiseReactionJob, « fulfillReaction, value »). 执行EnqueueJob(“PromiseJobs”,PromiseReactionJob,«fulfillReaction,value»)。

What this says is "if the promise is already pending, simply append the fulfillReaction of that pending promise, but of the promise is fulfilled, then enqueue a new job". 这说的是“如果承诺已经悬而未决,只需附加那个未决承诺的履行反应,但履行承诺,然后排队新工作”。

In other words, .then is guaranteed to return a pending promise regardless of whether the promise it is chained on was fulfilled or not . 换句话说, .then保证返回一个待处理的promise ,无论它被链接的promise是否满足

I think there is quite some confusion in both what happened with VSCode, what you asked as question, and the kind of answer you received. 我认为VSCode所发生的事情,你提出的问题以及你收到的答案都有些混乱。

I'll try to clarify all points as I can, hoping I got the question right. 我会尽力澄清所有观点,希望我能把问题弄清楚。

Let me start saying that ... 让我开始说......

Those two blocks are not equivalent 这两个街区并不相同

The following piece of code: 以下代码:

this
  .configure(config => {
    viewModel.configure(config, this);
    return config;
  })
  .then(value => `some ${value}`);

is " equivalent " only to this one: 只与这一个“ 等同 ”:

await this
  .configure(config => {
    viewModel.configure(config, this);
    return config;
  })
  .then(value => `some ${value}`);

That is because await has less priority than method chaining/ then concatenation. 这是因为await优先级低于方法链接/ then连接。

(async function (){
  const then = await Promise.resolve(1).then(one => one + one);
  console.log(then); // this is number 2
  const something = await 123;
  console.log(something); // this is number 123
}());

The reason you are rightly confused is that VSCode outsmarted your intent. 您正确混淆的原因是VSCode超出了您的意图。

  return this
    .configure(config => {
      viewModel.configure(config, this);
      // configure() returns a Promise
      // and config can be a Promise too
      return config;
    })
    .then(() => {
      // but you are not using here the config value
      // or, if it was a promise, whatever value it resolved
      // and you are also not returning any value
      this.activate();
    });

Since VSCode knows that configure is thenable , and its returned value could also be a Promise, which would imply the activate can happen only after config is eventually resolved, it also knows having an extra tick would make no sense because you don't need whatever config returned, either as value or promise, so that activate can be called right away. 由于VSCode知道configure可以的 ,并且它的返回值也可以是Promise,这意味着只有在最终解析了config之后才会发生activate ,它也知道有一个extra tick会没有意义,因为你不需要任何东西config返回,作为值或promise,以便可以立即调用activate

Since you were also not returning any value in the last then , the whole return can be dropped. 既然你还没有返回,在过去的任何值then ,整个return可以被丢弃。

// only async to wait for
await this.configure(config => {
  viewModel.configure(config, this);
  return config;
});
// with config either value or promise
// there's nothing else to wait for, so
// let's invoke activate without returning
// anything, producing is the same undefined result
this.activate();

To recap what happens inside that await: 重温内部发生的事情等待:

(async function (){
  const config = new Promise(res => setTimeout(res, 1000));
  console.time('awaiting');
  const value = await Promise.resolve(1).then(() => {
    return config;
  });
  console.timeEnd('awaiting');
  // awaiting: 1000.XXXms
}());

If you were by any chance using the returned value inside that last then , you would've seen that VSCode could not have dropped it, most-likely readdressed as const value = await ...; this.activate(value); 如果您在使用中,去年返回的值是通过任何机会then ,你就已经看到了VSCode不可能放弃了它,最可能重新定址为const value = await ...; this.activate(value); const value = await ...; this.activate(value); which is also still OK. 这还可以。


To the previous comment stating: 对上一条评论说:

For resolving a value, in plain terms, this: 为了解决价值,简单来说,这个:

await something

Is equivalent to this: 相当于:

Promise.resolve(something).then()

They both result in a pending promise. 他们都导致未决的承诺。

Not sure I read that wrong but that that felt to me quite a misleading statement. 不确定我读错了,但这对我来说是一个误导性的陈述。

const resolved = await anything means resolved is always a value, never a pending promise. const resolved = await anything意味着已resolved始终是一个值,而不是一个未决的承诺。

That's quite possibly the whole point of await : it won't stop awaiting until there is a value. 这很可能是await的全部内容:在有价值之前,它不会停止等待。

Example: 例:

(async function (){
  const something = Promise.resolve(Math.random());
  // this logs the random number as typeof number
  console.log(await something);
  // this also logs the random number as typeof number
  console.log(await Promise.resolve(something).then());
  // while this is one is the only pending promise
  console.log(Promise.resolve(something).then());
}());

The reason you eventually see Pending promise in console is that the AIIFE (Asynchronous Immediately Invoked Function Expression) is a promise itself and you can await it elsewhere. 您最终在控制台中看到Pending promise的原因是AIIFE(Asynchronous Immediately Invoked Function Expression)是一个承诺本身,您可以在其他地方等待它。

You can see that returning a value or a pending promise will always produce the expected result. 您可以看到返回值或挂起的promise将始终产生预期的结果。

(async function (){
  // instant return, it's just fine
  // return 123;

  // return promise (unnecessary ticks added)
  return Promise.resolve(123).then();
}()).then(console.log);

In both cases the 123 number is logged. 在这两种情况下都会记录123号码。

I hope it's clear now, specially for the OP, what happened in VSCode, and, specially, why happened. 我希望现在很清楚,特别是OP,在VSCode中发生了什么,特别是为什么会发生。

Regards. 问候。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM