打字机异步功能在负载过大时无法正常工作

时间:2018-04-18 18:51:29

标签: javascript typescript asynchronous promise

假设我有这个模块:

export async function beFancy () {
  let i, j, load;
  // just for trying to delay the return;
  for (i = 0; i < 999; ++i) {
    for (j = 0; j < 999; ++j) {
      load = i + j;
    }
  }
  return 'beFancy finished';
}

现在我制作了一个主要模块进行测试:

import {beFancy} from './mymodule';

beFancy().then((msg) => console.log(msg));
console.log('main finished');

如果我执行,输出是预期的

-> main finished
-> beFancy finished

因为beFancy是-asynchronous -

但是现在如果我试图使循环更加激烈:

export async function beFancy() {
  let i, j, load;
  for (i = 0; i < 9999999; ++i) {
    for (j = 0; j < 999; ++j) {
      load = i + j;
    }
  }
  return 'beFancy finished';
}

再次执行main,输出相同

-> main finished
-> beFancy finished

但我希望在实际处理函数main finished之前显示beFancy。相反,当beFancy完成时,上面的输出会一次显示。起初我认为原因是因为输出只在程序结束时刷新,但如果我输入:

console.log('begin');
beFancy().then((msg) => console.log(msg));
console.log('main finished');
“beFancy”执行前显示“开始”,因此我的先前假设未得到满足。

因为beFancy是 - 同步 - 可能是错的?这是我机器上的意外行为吗?

2 个答案:

答案 0 :(得分:1)

  

因为beFancy是 - 同步 - 可能是什么错误?

那是因为它只有beFancy返回的异步值。 beFancy主要是同步并阻塞主线程。上面的代码大致相同:

  function beFancy () {
    return new Promise(resolve => {
      let i, j, load;
      for (i = 0; i < 999; ++i) {
        for (j = 0; j < 999; ++j) {
          load = i + j;
        }
      }
      console.log('logged on same tick')
      resolve('logged on next tick');
    });
  }

  console.log('begin');
  beFancy().then((msg) => console.log(msg));
  console.log('main finished');

为了使async函数中的循环具有异步和非阻塞性,它应该使用await的块执行:

export async function beFancy () {
  let i, j, load;
  for (i = 0; i < 999; ++i) {
    await null; // next tick
    for (j = 0; j < 999; ++j) {
      load = i + j;
    }
  }
  return 'beFancy finished';
}

答案 1 :(得分:0)

JavaScript在单个线程上运行。通过利用异步非阻塞I / O,它可以实现多线程语言的性能平衡(有时甚至是优势)。

这很有效,因为大多数情况下,在多线程语言中,应用程序线程处于空闲状态,等待异步I / O请求返回。在JavaScript中,等待请求被停放,线程继续在其他地方执行。

当您在网络电话或磁盘上等待时,这很棒,但如果您的异步请求正在咀嚼CPU,那么线程就会随之而来。因此,上面为所有意图和目的使用的代码执行同步

这里是代码的执行顺序:

  1. 从主
  2. 开始
  3. 进入beFancy方法
  4. 坚持beFancy中的for循环
  5. 使用promise
  6. 返回main中的调用者
  7. 打印&#39;主要完成&#39;
  8. 解决了承诺
  9. 打印&#39; beFancy完成&#39;
  10. 使用setTimeout( () => console.log('done!'), 1500)替换CPU密集型for循环,您应该会看到预期的结果。