为什么不等待懒惰?

时间:2018-04-30 15:41:51

标签: javascript async-await

我很想了解为什么使用await立即阻止,而不是仅在引用await ed值时延迟阻止。

我希望这是一个有启发性/重要性的问题,但我担心这个问题可能被认为超出了本网站的范围 - 如果是这样我会道歉,稍微哭一下,并在其他地方提出问题。

E.g。请考虑以下事项:

let delayedValue = (value, ms=1000) => {
  return new Promise(resolve => {
    setTimeout(() => resolve(val), ms);
  });
};

(async () => {
  let value = await delayedValue('val');
  console.log('After await');
})();

在立即运行的匿名异步函数中,我们只会在延迟后看到控制台说After await。为什么这有必要?考虑到我们不需要解析value,为什么语言设计者决定不在这种情况下立即执行console.log语句?

例如,它与以下示例不同,延迟console.log显然是不可避免的(因为引用了await ed值):

(async () => {
  let value = await delayedValue('val');
  console.log('After await: ' + value);
});

我看到懒惰await阻塞有很多优点 - 它可能导致无关操作的自动并行化。例如。如果我想阅读两个文件,然后同时使用它们,我不会感到沮丧,我会写下以下内容:

(async() => {

  let file1 = await readFile('file1dir');
  let file2 = await readFile('file2dir');

  // ... do things with `file1` and `file2` ...

});

这将在开始阅读第二个文件之前等待读取第一个文件。但实际上它们可以并行读取,并且javascript应该能够检测到这一点,因为file1直到稍后才被引用。当我第一次学习异步/等待时,我最初的期望是上面的代码会导致并行操作,当结果证明是假的时候我有点失望。

让两个文件并行读取仍然有点混乱,即使在这个美丽的ES7世界中,因为await立即阻止而不是懒惰。你需要做类似下面的事情(这肯定比上面更麻烦):

(async() => {

  let [ read1, read2] = [ readFile('file1dir'), readFile('file2dir') ];
  let [ file1, file2 ] = [ await read1, await read2];

  // ... do things with `file1` and `file2` ...

});

为什么语言设计师选择让await立即阻止而不是懒惰?

E.g。它会导致调试困难吗?将懒惰的await集成到javascript中是否太难了?是否存在我没​​有想到懒惰await导致代码更加混乱,性能更差或其他负面后果的情况?

1 个答案:

答案 0 :(得分:2)

原因1:JavaScript没有被懒惰地评估。没有基础设施可以检测"何时需要一个值"。

原因2:隐含的并行性很难控制。如果我想要我的文件被顺序读取怎么办?我该怎么写呢?改变语法中的小东西不应导致非常不同的评估。

  

让两个文件并行读取仍然有点混乱

完全没有:

const [file1, file2] = await Promise.all([readFile('file1dir'), readFile('file2dir')]);
  

您需要执行以下操作

不,你absolutely shouldn't write it like that