延迟重试承诺,直到在 NodeJS 中解决

Retry promise with delay until resolved in NodeJS

我提前道歉,因为我是编程新手,而且我已经坚持了很长一段时间。我有一个 connect() 函数,它 returns 一个承诺(它也嵌入在 class - 未显示)。如果未建立连接(即返回拒绝),我希望此功能延迟重试,但我一直无法这样做;我尝试使用异步 js 库和 promise-retry 库无济于事 - 我无法理解文档。为清楚起见,如果建立连接,socket.connect 会发出 'connect' 函数。

this.socket = new net.Socket();
this.client = new Modbus.client.TCP(this.socket, this.unitID);
const net = require('net');
const Modbus = require('jsmodbus');


connect() {

    return new Promise((resolve, reject) => {

        this.socket.connect(options);

        this.socket.on('connect', () => {

            logger.info('*****CONNECTION MADE*****');

            //does something once connection made

            resolve();
        });

        this.socket.on('error', (error) => {
            logger.error('failed to connect');
            this.disconnect();
            reject();
        });
    })
}

首先定义一个延迟的效用函数:

const delay = ms => new Promise(resolve => setTimeout(resolve, ms));

然后将 .catch 处理程序链接到 new Promise:

.catch(() => delay(1000).then(() => this.connect()));

当然,您应该避免无限次重试。所以实现一些逻辑来确定放弃:在尝试固定次数后,或者在一定时间过去后,...等等

例如,给connect一个参数应该允许多少次尝试:

connect(attempts=3) {

那么捕获处理程序可以是:

.catch((err) => {
     if (--attempts <= 0) throw err; // give up
     return delay(1000).then(() => this.connect(attempts));
});

我会通过进行一次连接尝试的函数来做到这一点(基本上,将您的 connect 重命名为 tryConnect 或类似的,如果您正在使用,甚至可能作为私有方法Node.js 的一个足够新的版本),然后有一个用重复和延迟调用它的函数,就像这样(见评论):

效用函数:

function delay(ms, value) {
    return new Promise(resolve => setTimeout(resolve, ms, value);
}

connect:

async connect() {
    for (let attempt = 0; attempt < MAX_ATTEMPTS; ++attempt) {
        if (attempt > 0) {
            // Last attempt failed, wait a moment
            await delay(RETRY_DELAY_IN_MS);
        }
        try {
            await tryConnect();
            return; // It worked
        } catch {
        }
    }
    // Out of retries
    throw new Error("Couldn't create connection");
}

(如果您使用的是稍旧的 Node.js,您可能需要在上面的 catch 之后添加 (e)。不使用时将其关闭不需要它是一个相对较新的功能。)


关于你当前对我所说的实现 tryConnect,这里有一些注释作为我将如何更改它的评论:

tryConnect() {
    return new Promise((resolve, reject) => {
        // Keep these local for now
        const socket = new net.Socket();
        const client = new Modbus.client.TCP(socket, this.unitID);

        // Add handlers before calling `connect
        socket.on('connect', () => {

            logger.info('*****CONNECTION MADE*****');

            // NOW save these to the instance and resolve the promise
            this.socket = socket;
            this.client = client;
            resolve();
        });

        socket.on('error', (error) => {
            logger.error('failed to connect');
            // It's not connected, so no `disconnect` call here
            reject();
        });

        socket.connect(options);
    });
}

在调用connect的函数中, 可以递归调用,eg

const outerFunction = (times = 0) => {
  if (times < 4) {
    socket
      .connect(params)
      .then(() => {
        // do good stuff
      })
      .catch(e => {
        // increment the times so that it wont run forever
        times++;
          setTimeout(() => {
            // delay for two seconds then try conecting again
          outerFunction(times);
        }, 2000);
      });
  }
};

这样你的connect函数就以2秒的间隔尝试了3次,希望能解决你的问题