异步是否在浏览器中等待真正的非阻塞?

时间:2017-03-13 21:26:31

标签: javascript user-interface asynchronous async-await ecmascript-2017

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

所以我的问题是:

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

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

  • async / await如何与先前的异步功能(例如setTimeout和XmlHttpRequest)相关?

5 个答案:

答案 0 :(得分:51)

当承诺await p结算时,

p会安排执行其余功能。这就是全部。

async可让您使用await。它(几乎)所有这一切(它也将你的结果包装在一个承诺中)。

它们一起使非阻塞代码读取就像更简单的阻塞代码。他们不会取消阻止代码。

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



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));
&#13;
&#13;
&#13;

答案 1 :(得分:13)

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

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

答案 2 :(得分:9)

JavaScript是单线程的,并且在与UI相同的线程中运行。所以所有JavaScript代码都会阻止UI。正如其他人所提到的,Web worker可以用来在其他线程中运行代码,但它们有局限性。

异步函数和常规函数之间的区别在于它们返回一个promise。使用回调,您可以延迟执行代码,处理函数调用的结果,从而允许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是承诺的回调不会立即执行。

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。就像承诺的回调一样,await之后的代码永远不会立即执行。

答案 3 :(得分:1)

developer.mozilla.org的描述中可以明显看出它是非阻塞的:

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

答案 4 :(得分:0)

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

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

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