60

我一直在使用 TypeScript 和本机 Promises 在 SPA 中使用该功能,我注意到即使我将长时间运行的函数重构为返回 promise 的异步函数,UI 仍然没有响应。

所以我的问题是:

  • 新的 async/await 功能究竟如何帮助避免阻塞浏览器中的 UI?在使用 async/await 来实际获得响应式 UI 时,是否需要采取任何特殊的额外步骤?

  • 有人可以创建一个小提琴来演示 async/await 如何帮助使 UI 响应吗?

  • async/await 与 setTimeout 和 XmlHttpRequest 等先前的异步功能有何关系?

4

5 回答 5

99

await pp当 promise解决时,安排执行其余的函数。就这样。

async让您使用await. 这就是(几乎)它所做的一切(它还将你的结果包装在一个承诺中)。

它们一起使非阻塞代码像更简单的阻塞代码一样读取。他们不会解锁代码。

对于响应式 UI,将 CPU 密集型工作卸载到工作线程,并将消息传递给它:

async function brutePrime(n) {
  function work({data}) {
    while (true) {
      let d = 2;
      for (; d < data; d++) {
        if (data % d == 0) break;
      }
      if (d == data) return self.postMessage(data);
      data++;
    }
  }

  let b = new Blob(["onmessage =" + work.toString()], {type: "text/javascript"});
  let worker = new Worker(URL.createObjectURL(b));
  worker.postMessage(n); 
  return await new Promise(resolve => worker.onmessage = e => resolve(e.data));
}

(async () => {
  let n = 700000000;
  for (let i = 0; i < 10; i++) {
    console.log(n = await brutePrime(n + 1));
  }
})().catch(e => console.log(e));

于 2017-03-15T03:22:11.350 回答
27

async是构造异步代码的一种更优雅的方式。它不允许任何新功能;它只是比回调或承诺更好的语法。

因此,async不能用于“使某些东西异步”。如果您的代码必须执行大量基于 CPU 的处理,async则不会神奇地使 UI 响应。您需要做的是使用web workers之类的东西,这将 CPU 绑定的工作推送到后台线程以使 UI 响应的适当工具。

于 2017-03-14T02:03:11.963 回答
22

JavaScript 是单线程的,并且与 UI 在同一个线程中运行。所以所有的 JavaScript 代码都会阻塞 UI。正如其他人提到的,网络工作者可用于在其他线程中运行代码,但它们有局限性。

异步函数和常规函数之间的区别在于它们返回一个承诺。使用回调,您可以延迟代码的执行,该代码处理函数调用的结果,从而允许 UI 完成一些工作。以下三个示例具有相同的效果:

async function foo() {
  console.log("hi");
  return 1; 
}
foo().then(result => console.log(result))
console.log("lo");

function foo() {
  console.log("hi");
  return 1; 
}
Promise.resolve(foo()).then(result => console.log(result))
console.log("lo");

function foo() {
  console.log("hi");
  return 1; 
}
const result = foo();
setTimeout(() => console.log(result));
console.log("lo");

在所有三种情况下,控制台都会记录 hi, lo, 1。在打印 1 之前,UI 可以处理用户输入或绘制更新。在前两种情况下最后打印的原因 1 是 promise 的回调没有立即执行。

await允许您在没有回调的情况下做到这一点:

async function foo() {
  console.log("hi");
  return 1; 
}

async function bar() {
  const result = await foo();
  console.log(result);
}

bar();
console.log("lo"); 

这也将打印 hi, lo, 1。就像 promise 的回调一样,后面的代码await永远不会立即执行。

于 2017-03-16T12:11:48.270 回答
2

developer.mozilla.org上的描述可以清楚地看出它是非阻塞的:

await 关键字会导致 JavaScript 运行时暂停您的代码在此行,同时允许其他代码执行(注意:我的粗体),直到异步函数调用返回其结果。完成后,您的代码将从下一行开始继续执行。

于 2020-10-12T21:28:55.860 回答
0

我在这里聚会迟到了。我想验证同步和异步用例。

需要明确的是,async/await 不会创建同步代码。它只是增加syntactic sugar了使代码看起来是同步的。在包装器下,Promise 逻辑继续实现non-preemptive multitasking

在示例gist中,您可以使用选择阻塞或非阻塞 CLI 输入的命令行参数运行示例。 asyncExample.js

于 2021-07-09T02:34:46.133 回答