【问题标题】:How to make this non-blocking in Nodejs?如何在 Nodejs 中实现非阻塞?
【发布时间】:2022-02-17 16:09:38
【问题描述】:

我必须继续调用 SERVICE_PATH,直到响应中的报告准备好。
显然,由于使用了“do/while”,下面的代码被阻塞了。
那么,问题是如何重构代码以使其成为非阻塞的?

let scoring_report;
let timeout_count = 1;
let getReport;
do {
    await new Promise((resolve) => setTimeout(resolve, timeout_count * 1000));
    getReport = await axios.post(`${process.env.SERVICE_PATH}:8001`, {body});
    scoring_report = getReport.data.data.reportBase64;
    timeout_count += 2;
  } while (!scoring_report);

【问题讨论】:

  • 最好使用工作线程或一些调度程序在 N 分钟/秒内执行一次
  • "显然,由于使用了"do/while"",下面的代码被阻塞了。不,不是。
  • @Kaiido 我认为JS代码通常负责阻塞,因为主线程很忙,并且在主线程计算时不要让事件循环干扰。能详细点吗?
  • 好吧,你的异步函数被 await 关键字暂停,它只会在它等待的 Promise 解决时恢复,并且只有在执行超时回调后才会发生。在这两者之间,这个脚本不会做任何事情,也不会让事件循环保持忙碌。
  • @Kaiido 我明白了,但在我的情况下,do/while 取决于 score_report,它是 POST 请求(getReport)的响应。因此,do/while 使主线程保持忙碌,而异步请求(getReport)继续调用,直到它收到具有“reportBase64”的响应。这就是为什么我认为 do/while 是阻塞的。我在这里误解了什么吗?

标签: javascript node.js nonblocking event-loop


【解决方案1】:

您的代码被阻止不是由于do... while..。这要归功于async await

阻止代码示例。

async function resolveAfterSomeTime() {
  let counter = 0;
  do {
    console.log("starting promise")
    const x = await new Promise(resolve => {
      setTimeout(function () {
        resolve("done")
        console.log("promise is done")
      }, 800)
    });
    counter++;
    console.log(x);
  } while (counter < 5);
}
resolveAfterSomeTime();

如您所见,由于async await,上述代码每次执行都会阻塞 800 毫秒。

您可以通过简单地删除async await 来使其成为非阻塞。如果您对结果不感兴趣,您可以简单地调用该函数并进行下一个迭代。在下面的代码中,x 的值将是一个承诺,您可以使用 x.then((resp) =&gt; console.log(resp)) 检查承诺的已解决状态以处理您的进一步逻辑

示例代码。

function resolveAfterSomeTime() {
  let counter = 0;
  do {
    console.log("starting promise")
    const x = new Promise(resolve => {
      setTimeout(function () {
        console.log("promise is done");
        resolve("done");
      }, 800)
    });
    counter++;
    x.then((resp) => console.log(resp))
  } while (counter < 5);
}
resolveAfterSomeTime();

您的示例非阻塞代码

let scoring_report;
let timeout_count = 1;
let getReport;
do {
  new Promise((resolve) => setTimeout(resolve, timeout_count * 1000));
  // here getReport will be a promise
  getReport = axios.post(`${process.env.SERVICE_PATH}:8001`, { body });
  // Use getReport.then((data) => {}) for further logic
} while (!scoring_report);

使用setInterval实现

如果你只想在指定的时间间隔执行函数,你可以使用setInterval,它不会阻塞你的主线程。一旦需要的结果可用,不要忘记clearInterval

示例实施

let scoring_report;
let timeout_count = 1;
let getReport;

const myInterval = setInterval(() => {
  getReport = await axios.post(`${process.env.SERVICE_PATH}:8001`, { body });
  scoring_report = getReport.data.data.reportBase64;
  timeout_count += 2;
  if(scoring_report) {
    clearInterval(myInterval)
  }
}, timeout_count * 1000);

【讨论】:

  • 我在 getReport.then 中进行了scoring_report 检查,就像这样 getReport.then( (data)=>scoringreport =data.data.reportBase64 ) 我得到了这个错误:致命错误:无效的标记压缩附近堆限制分配失败 - JavaScript 堆内存不足
  • 不是“阻塞”,而是暂停。如果在等待计时器时必须做其他事情,它将完成。这就是我们所说的“非阻塞”。
  • @Rass_Rukh 这段代码的目的是什么? new Promise((resolve) =&gt; setTimeout(resolve, timeout_count * 1000));
  • @Nitheesh 的目的只是等待(n*1sec)然后发出请求(getReport)。我需要的是重复请求(每 n*1 秒或 1 分钟),直到 SERVICE_PATH 在响应中有 getReport。
  • @Rass_Rukh 最好使用setInterval 而不是异步等待。用这个实现更新了答案。
猜你喜欢
  • 2016-08-26
  • 1970-01-01
  • 1970-01-01
  • 2013-08-22
  • 1970-01-01
  • 2016-03-24
  • 2013-06-24
  • 2019-05-31
  • 1970-01-01
相关资源
最近更新 更多