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

prm*_*mph 30 javascript user-interface asynchronous async-await ecmascript-2017

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

所以我的问题是:

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

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

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

jib*_*jib 56

await p在promise p解析时安排执行其余功能.就这样.

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));
Run Code Online (Sandbox Code Playgroud)

  • 没有外部文件的工人的分数.这是一个很酷的技巧. (11认同)

Ste*_*ary 14

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

所以,async不能用来"做一些异步".如果您的代码必须执行大量基于CPU的处理,async则不会神奇地使UI响应.您需要做的是使用类似Web工作者的东西,这将CPU绑定工作推送到后台线程以使UI响应的适当工具.

  • @ Martian2049:是的; `async`是建立在Promise上的,它是非阻塞的. (2认同)
  • @abetteroliver:也许我们正在研究不同的语义。当我说“[async] 不允许任何新功能”时,我的意思是,你可以使用 `async` 做的所有事情都可以在没有 `async` 的情况下使用回调/promises 来完成——这是微不足道的,因为直到最近 `async` 都是没有运行时支持的编译时代码转换。 (2认同)

a b*_*ver 11

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");
Run Code Online (Sandbox Code Playgroud)

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

await 允许您在没有回调的情况下执行此操作:

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

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

bar();
console.log("lo"); 
Run Code Online (Sandbox Code Playgroud)

那也将打印hi,lo,1.就像一个承诺的回调一样,后面的代码await永远不会立即执行.

  • @Rodrigo你只能在异步函数中等待。 (2认同)
  • @zzzzzzzz 异步函数返回一个承诺。`await` 等待承诺被解析或拒绝,并且这总是异步发生。严格意义上没有等待时间,只是在此之前执行了任何同步代码。 (2认同)