【问题标题】:How to stop running async function on node.js from react application?如何从反应应用程序停止在 node.js 上运行异步功能?
【发布时间】:2022-01-26 00:55:42
【问题描述】:

React 应用程序可以运行 node.js 函数,该函数可以批量准备数据并将信息发送到数据库。 这需要很多时间,我想添加从 react 应用程序中直接停止此功能的功能。

const getShopifyOrders = require('./shopify');
const getTrack = require('./tracking');
const Order = require('./model');

async function addOrdersToDB(limit) {
  try {
    // Get latest order from DB
    let latestOrd = await Order.findOne().sort('-order_number');

    do {
      // Get Shopify Orders
      let orders = await getShopifyOrders(
        latestOrd ? latestOrd.order_id : 0,
        limit
      );
      latestOrd = orders[0] ? orders[orders.length - 1] : undefined;

      // Update array with tracking status
      let fullArray = await getTrack(orders);

      // Add to DB
      let ins = await Order.insertMany(fullArray, { ordered: false });
      console.log(`Added ${ins.length} entries`);
    } while (latestOrd);
  } catch (err) {
    console.log(err);
  }
}
module.exports = addOrdersToDB;

我尝试了很多东西来包含在这个函数中,包括:

  • while 循环:在函数外部添加变量 - 如果为“真” - 运行代码,如果不是 - 返回 - 它只是不起作用(变量已从使用 socket.IO 的反应中更改)

  • setTimeout(也称为 setInterval),从 react 触发 clearTimeout 函数:这在 setTimeout 中不起作用,而 setInterval 在异步函数中不起作用

之后:

  • 制作了(实际上在 stackoverflow 上很喜欢)新函数来承诺 setTimeout 能够在异步函数中使用:
const setTimeout2 = (callback, ms) => {
  return new Promise(
    resolve =>
      (to = setTimeout(() => {
        callback();
        resolve();
      }, ms))
  );
};
async function addOrdersToDB(limit) {
  do {
    await setTimeout2(async () => {
      try {
        // some code here
      } catch (err) {
        console.log(err);
      }
    }, 400);
  } while (latestOrderExist);
}
function clearTO() {
  setTimeout(() => {
    console.log('clearTO');
    clearTimeout(to);
  }, 3000);
}

由于某种原因,这不会迭代。

有解决办法吗? 谢谢!

【问题讨论】:

  • 您能否为您要解决的实际问题显示代码。在 nodejs 中没有通用的方法来停止异步操作。每种类型的异步操作都是不同的。例如,您可以通过调用clearTimeout(timerid) 来停止setTimeout(),但没有办法停止fs.readFile()。因此,这完全取决于异步操作,因此我们需要查看真正的代码以及您要解决的实际问题。
  • 请用您的实际代码发布问题。由于一些未知的原因,人们认为编写伪代码并提出某种通用问题会更好。这几乎从来都不是为您的问题找到一个好的答案的最佳方法。对于初学者来说,只有当我们看到您的实际代码时,我们才能看到实际和真正的问题,此外,当我们看到您的真实代码时,有时我们可以为您提供比您甚至想问的更好的解决方案。此外,当您将其提炼为伪代码时,人们通常会遗漏问题的重要细节。
  • 刚刚添加了 node.js 代码。谢谢!
  • 在你的真实代码中,你试图从外部中止什么?您是否尝试在您的第一个代码块中中止 do/while 循环?
  • 是的,我试图中止 do/while 循环。

标签: javascript node.js reactjs sockets socket.io


【解决方案1】:

要中止do/while 循环,您需要向该循环添加一个额外的测试,该测试是一些可以从外部修改的变量。另外,请注意,附加测试仅在此处有效,因为您在循环中使用了await。如果循环内没有await,那么循环将是完全同步的,并且在循环运行时将无法从循环外更改变量(因为 nodejs 的单线程性)。

由于这是一个服务器(全局变量通常不好),我假设我们不应该使用全局变量。因此,相反,我将重构addOrdersToDB() 以返回一个数据结构,其中包含现有版本返回的承诺和调用者可以调用以停止当前处理的abort() 函数。这也允许对 addOrdersToDB() 的多个单独调用运行,每个调用都有自己单独的 abort() 方法。

function addOrdersToDB(limit) {
    let stop = false;

    function abort() {
        stop = true;
    }

    async function run() {
        try {
            // Get latest order from DB
            let latestOrd = await Order.findOne().sort('-order_number');

            do {
                // Get Shopify Orders
                let orders = await getShopifyOrders(
                    latestOrd ? latestOrd.order_id : 0,
                    limit
                );
                latestOrd = orders[0] ? orders[orders.length - 1] : undefined;

                // Update array with tracking status
                let fullArray = await getTrack(orders);

                // Add to DB
                let ins = await Order.insertMany(fullArray, { ordered: false });
                console.log(`Added ${ins.length} entries`);
            } while (!stop && latestOrd);

            // make resolved value be a boolean that indicates
            // whether processing was stopped with more work still pending
            return !!(latestOrd && stop);

        } catch (err) {
            // log error and rethrow so caller gets error propagation
            console.log(err);
            throw err;
        }
    }
    return {
        promise: run(),
        abort: abort
    }
}

因此,要使用它,您必须更改调用addOrdersToDB() 的方式(因为它不再只返回一个承诺)并且您必须捕获它返回的abort() 函数。然后,代码的其他部分可以调用abort() 函数,然后它会翻转内部stop 变量,这将导致do/while 循环停止任何进一步的迭代。

注意,这不会停止 do/while 循环当前迭代内的异步处理 - 它只是停止循环的任何进一步迭代。

请注意,我还更改了您的 catch 块,以便它重新引发错误,以便调用者查看是否/何时出现错误。

而且,函数的解析值是内部stop 变量,因此调用者可以查看循环是否中止。 true 解析值表示循环已中止,还有更多工作要做。


这是该函数的一个附加版本,它创造了更多机会让它在您的函数内和循环内的 await 操作之间停止。这仍然不会中止可能正在进行的单个数据库操作 - 您必须检查您的数据库是否支持此类操作,如果支持,如何使用它。

function addOrdersToDB(limit) {
    let stop = false;

    function abort() {
        stop = true;
    }

    async function run() {
        try {
            // Get latest order from DB
            let latestOrd = await Order.findOne().sort('-order_number');

            if (!stop) {
                do {
                    // Get Shopify Orders
                    let orders = await getShopifyOrders(
                        latestOrd ? latestOrd.order_id : 0,
                        limit
                    );
                    latestOrd = orders[0] ? orders[orders.length - 1] : undefined;
                    if (stop) break;

                    // Update array with tracking status
                    let fullArray = await getTrack(orders);
                    if (stop) break;

                    // Add to DB
                    let ins = await Order.insertMany(fullArray, { ordered: false });
                    console.log(`Added ${ins.length} entries`);
                } while (!stop && latestOrd);
            }

            // make resolved value be a boolean that indicates
            // whether processing was stopped with more work still pending
            return !!(latestOrd && stop);

        } catch (err) {
            // log and rethrow error so error gets propagated back to cller
            console.log(err);
            throw err;
        }
    }
    return {
        promise: run(),
        abort: abort
    }
}

【讨论】:

  • 谢谢!!出于某种原因,它在运行中止功能时显示“E11000 重复键错误集合:tracking.orders index: order_number_1 dup key”。但现在我知道该往哪个方向发展了。
  • 你说:它不会停止do/while循环当前迭代中的异步处理。是否可以停止这个异步进程?
  • @NeoN - 你到底想阻止什么?您可以在每个 await 语句之间添加对 stop 变量的额外检查,并在它们之间中止(我可以将其添加到答案中)。如果你想中止一个实际运行的数据库操作,那将取决于你的数据库是否可行。
  • @NeoN - 添加到我的答案中的新版本也将在数据库操作之间停止,而不仅仅是在循环迭代结束时。
猜你喜欢
  • 2017-08-16
  • 2016-05-22
  • 2016-08-10
  • 1970-01-01
  • 2015-03-18
  • 1970-01-01
  • 2023-03-23
  • 2017-06-20
  • 1970-01-01
相关资源
最近更新 更多