【问题标题】:Does top-level await have a timeout?顶级等待是否有超时?
【发布时间】:2021-12-29 21:21:22
【问题描述】:

top-level await 被 ES2022 接受,我想知道是否可以假设 await import("./path/to/module") 根本没有超时。 这是我想做的:

// src/commands/do-a.mjs

console.log("Doing a...");
await doSomethingThatTakesHours();
console.log("Done.");
// src/commands/do-b.mjs

console.log("Doing b...");
await doSomethingElseThatTakesDays();
console.log("Done.");
// src/commands/do-everything.mjs

await import("./do-a");
await import("./do-b");

这是我在运行node src/commands/do-everything.mjs 时期望看到的:

Doing a...
Done.
Doing b...
Done.

我找不到任何关于顶级等待超时的提及,但我想知道我试图做的是否是对该功能的滥用。理论上,Node.js(或 Deno)可能会在达到某个预定义的时间上限(例如 30 秒)后抛出异常。

这是我在 TLA 之前处理相同任务的方式:

// src/commands/do-a.cjs
import { autoStartCommandIfNeeded } from "@kachkaev/commands";

const doA = async () => {
  console.log("Doing a...");
  await doSomethingThatTakesHours();
  console.log("Done.");
}

export default doA;

autoStartCommandIfNeeded(doA, __filename);
// src/commands/do-b.cjs
import { autoStartCommandIfNeeded } from "@kachkaev/commands";

const doB = async () => {
  console.log("Doing b...");
  await doSomethingThatTakesDays();
  console.log("Done.");
}

export default doB;

autoStartCommandIfNeeded(doB, __filename);
// src/commands/do-everything.cjs
import { autoStartCommandIfNeeded } from "@kachkaev/commands";
import doA from "./do-a";
import doB from "./do-b";

const doEverything = () => {
  await doA();
  await doB();
}

export default doEverything;

autoStartCommandIfNeeded(doEverything, __filename);

autoStartCommandIfNeeded()__filename 匹配require.main?.filename 时执行函数。

【问题讨论】:

  • await 没有内置任何超时,无论是顶级还是非顶级。
  • 注意:我没有看到任何 try/catch.catch() 与您的任何承诺一起使用。如果其中任何一个可以拒绝,您将无法控制情况。
  • 谢谢@jfriend00!你所说的受控情况是什么意思?只要我们不开始运行do-b 如果do-a 失败,流程就会为我工作。我期望一个非零退出代码和一个堆栈跟踪,应该 doSomethingThatTakesHours() 抛出(即拒绝)。
  • 是的,将堆栈跟踪输出到 stderr 是我认为不受控制的情况。您无法控制出现错误时会发生什么。它只会退出而不运行您的任何代码。一般来说,不是你将如何设计的东西。我提到了缺少错误处理,因为这是使用await 编程时非常常见的错误。但是,如果你想那样做,那就去吧。
  • 其实你提的很好!当我使用autostartCommandIfNeeded() 时,我可以控制如何显示未捕获的异常,从而改进命令用户体验。这在顶级等待中会丢失,但我想我们可以通过process.on('uncaughtException', handler) 修复它。例如。我们可以在每个命令中添加import "./path/to/beautify-uncaught-exceptions",这样就可以了!这些命令将不受顶级函数定义和调用的影响。如果没有 TLA 超时,这似乎是不必要的开销!

标签: node.js async-await node-modules es6-modules ecmascript-2021


【解决方案1】:

回答:不,await 没有顶级超时。

这个特性实际上是在 Deno 中用于网络服务器的,例如:

import { serve } from "https://deno.land/std@0.103.0/http/server.ts";

const server = serve({ port: 8080 });
console.log(`HTTP webserver running.  Access it at:  http://localhost:8080/`);

console.log("A");

for await (const request of server) {
  let bodyContent = "Your user-agent is:\n\n";
  bodyContent += request.headers.get("user-agent") || "Unknown";

  request.respond({ status: 200, body: bodyContent });
}

console.log("B");

在此示例中,“A”在控制台中打印,而“B”则在网络服务器关闭(这不会自动发生)之前打印。

【讨论】:

    【解决方案2】:

    据我所知,async-await 默认没有超时。例如,有一个 await-timeout 包,它正在添加超时行为。示例:

    import Timeout from 'await-timeout';
     
    const timer = new Timeout();
    try {
      await Promise.race([
        fetch('https://example.com'),
        timer.set(1000, 'Timeout!')
      ]);
    } finally {
      timer.clear();
    }
    

    取自文档:https://www.npmjs.com/package/await-timeout

    如您所见,Timeout 被实例化,其set 方法定义了超时和超时消息。

    【讨论】:

      猜你喜欢
      • 2022-09-28
      • 1970-01-01
      • 1970-01-01
      • 2020-06-08
      • 2022-11-23
      • 2021-03-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多