【问题标题】:NodeJS: Async function still halts main function [duplicate]NodeJS:异步函数仍然暂停主函数[重复]
【发布时间】:2022-02-14 10:32:10
【问题描述】:

我正在尝试让一个函数调用一些代码,同时让我的主函数继续运行而不必等待它。

到目前为止它还没有工作:

function doSomething() {
  return new Promise((resolve, reject) => {
    if(1) {
        console.log("doing something");
        for(let i = 0; i < 10000; i++) {
            for(let j = 0; j < 10000; j++) {
                for(let k = 0; k < 100; k++) {
                 // Do something for a long time to check if async is working
                }
            }
        }
        console.log("finished doing something");
        resolve( {"dummydata": 10} );
    }
    else {
        reject("error!");
    }
  })
}

function main() {
    doSomething()
    .then(data => console.log(data))
    .catch(err => console.error(err))

    console.log("this should print before doSomething() is finished");
}

main();

这是输出:

做某事

做完一件事

这应该在 doSomething() 完成之前打印

{ 虚拟数据:10 }

为什么我的程序在等待 doSomething()?我希望它并行/异步运行。我还尝试将 main() 设为异步函数,与 doSomething() 相同,但这不起作用。

【问题讨论】:

  • 因为你实际上并没有做任何异步的事情,那么你对应该发生的事情的猜测实际上是错误的......将代码包装在一个 setTimeout 中的 promise 执行器中,那么你将做一些异步的事情,不只是陈述一个错误的断言
  • Promises 是一种用于处理固有异步任务的实用程序。不是为了让代码并行运行。

标签: javascript node.js asynchronous promise


【解决方案1】:

JavaScript 仍然是单线程的。如果你有一段昂贵的代码,比如你的嵌套循环,并且你没有在循环内await,那么当循环迭代时,你环境中的所有其他 JavaScript 处理都将被阻塞 - 控制流只会在所有循环中返回同步代码已完成。

放在 Promise 构造函数回调顶层的代码会立即运行 - 执行 return new Promise 不会使代码放在单独的线程或类似的东西上。

虽然您可以排队任务,让它在延迟后启动,并让主脚本继续它需要做的任何事情:

function main() {
  setTimeout(doSomething, 2000);
  // more code

要真正并行运行它,您需要使用child_process。将脚本的昂贵部分放入自己的文件中,并让 child_process 通过.fork 调用它。

【讨论】:

  • 不需要单独的进程,一个工作线程就足够了。
  • @Bergi 等待那么 app.listen() (app = express()) 如何在同一个线程上异步运行代码?还是它也使用child_process?我可以调用 app.listen(),让它监听事件,同时运行其他代码。如果 javascript 是单线程的,这将如何工作?
  • @RanShorowitz 只是 listening 事件或消息不需要像在循环中那样连续运行代码 - 它只需要其他进程连接到您的代码中,这最终导致回调运行。如果您的 Express 应用程序中存在严重循环,则多个请求可能会出现延迟,直到前一个请求的循环完成。
【解决方案2】:

你可以使用worker_threads:https://nodejs.org/api/worker_threads.html#worker-threads

const { Worker } = require("worker_threads");

const worker = new Worker(
  `
const { parentPort } = require('worker_threads');

parentPort.postMessage("doing something");
  for (let i = 0; i < 10000; i++) {
    for (let j = 0; j < 10000; j++) {
      for (let k = 0; k < 100; k++) {
        // Do something for a long time to check if async is working
      }
    }
  }
  parentPort.postMessage("finished doing something");
  parentPort.postMessage({ dummydata: 10 });

`,
  { eval: true }
);
worker.on("message", (message) => console.log(message));

console.log("this should print before doSomething() is finished");

这只是一个sn-p。可以和worker等交换数据……

【讨论】:

  • worker_thread和child_process有什么区别?
  • 来自 nodejs 文档:Unlike child_process or cluster, worker_threads can share memory. 这里也是这个主题:stackoverflow.com/questions/56312692/…
  • 啊。此外,您发布的代码似乎没有异步运行?该程序似乎在等待工作人员完成后再执行其他任何操作。
  • @RanShorowitz worker 的代码是并行执行的。 asynchronously 是什么意思?实际上,JavaScript 是单线程的,因此所有异步函数都在同一个线程上执行*(请参阅底部的链接)。在使用线程时,您可以在工作人员的代码并行运行后做任何您想做的事情,这与您的程序会滞后的 js async 不同。当您运行上面的代码时,node.js 将等待所有工作人员结束执行。由于上面的脚本做的不多,调用worker之后,nodejs会等待worker完成。 stackoverflow.com/a/61134366/11963457
猜你喜欢
  • 1970-01-01
  • 2021-11-02
  • 2021-07-14
  • 2021-11-07
  • 2020-03-26
  • 2019-03-24
  • 1970-01-01
  • 2015-12-01
  • 1970-01-01
相关资源
最近更新 更多