递归承诺失败

时间:2017-05-31 11:13:49

标签: javascript node.js sockets

背景

我正在尝试使用Node.js中的net.Socket连接到计算机。有时连接正常,我成功,有时连接断开,所以我一直在重试。

目的

我想编写一个reconnect方法,尝试连接到IP。当它成功时,它会结算,但如果它失败了它应该继续尝试。

代码

    const reconnect = function ( connectOpts ) {
        return new Promise( resolve => {
            connect( connectOpts )
                .then( () => {
                    console.log( "CONNECTED " );
                    resolve();
                } )
                .catch( () => {
                    console.log( "RETRYING" );
                    connect( connectOpts );
                } );
        } );
    };

    const connect = function ( connectOpts ) {
        return new Promise( ( resolve, reject ) => {
            socket = net.createConnection( connectOpts );

            //once I receive the 1st bytes of data, I resolve();
            socket.once( "data", () => {
                resolve();
            } );

            socket.once( "error", err => reject( err ) );
        } );
    };

reconnect({host: localhost, port: 8080})
    .then(() => console.log("I made it!"));

问题

问题是,当连接失败时,它只会再次尝试,然后它会爆炸!

问题

如何更改我的代码,以便每次失败时都会重新连接? PS:此功能非常重要异步

4 个答案:

答案 0 :(得分:0)

正如您正确指出的那样,当您尝试从.catch()方法进行连接时,代码会爆炸。

.catch( () => {
                console.log( "RETRYING" );
                connect( connectOpts );
            } );

有两个选项可以解决这个问题

选项1:使用ES6 Generator功能

我最近遇到了类似的问题,我使用生成器函数来解决我的问题。本质上,生成器函数允许您暂停执行,直到异步任务完成。然后,您可以根据异步任务的结果继续执行

参考 - https://eladnava.com/write-synchronous-node-js-code-with-es6-generators/

选项2-使用延期承诺

您可以对此用例使用称为延迟承诺的内容。更多细节 - https://mostafa-samir.github.io/async-recursive-patterns-pt2/

此外,类似的stackoverlow问题在这里 - execute promises recursively nodejs

希望有所帮助!

答案 1 :(得分:0)

试试这个:

const connect = function(connectOpts) {

  const connectResolver = (resolve) => {
    socket = net.createConnection(connectOpts);
    socket.once("data", resolve);
    socket.once("error", () => 
      // you can try setTimeout() here with specific retry in milliseconds here
      // say like setTimeout(() => connectResolver(resolve), 200);
      // instead of immediate retry in the end of every event loop
      // up to you
      setImmediate(() => connectResolver(resolve)));
  }

  return new Promise(connectResolver);
};

connect({
    host: localhost,
    port: 8080
  })
  .then(() => console.log("I made it!"));

答案 2 :(得分:0)

检查代码,我发现了这个。

  • 重试永远不会是resolvereject。然后UnhandledPromiseRejectionWarning可能会发生。

然后让我们在reconnect处理程序中调用.catch。解决后,通过调用resolve()来解决Promise问题。

    const reconnect = function ( connectOpts ) {
        return new Promise( resolve => {
            connect( connectOpts )
            .then( () => {
                console.log( "CONNECTED " );
                resolve();
            } )
            .catch( () => {
                console.log( "RETRYING" );

                // connect( connectOpts );

                return reconnect( connectOpts )
                .then(() => {
                    resolve();
                });

            } );
        } );
    };

答案 3 :(得分:0)

我的解决方案

在阅读完所有其他解决方案之后,我最终选择了这个:

   const reconnect = async function ( connectOpts ) {
        let done = false;
        while ( !done ) {
            done = await connect( connectOpts )
                .then( () => true )
                .catch( () => false );
        }
    };

const connect = function ( connectOpts ) {
        return new Promise( ( resolve, reject ) => {
            socket = net.createConnection( connectOpts );

            //once I receive the 1st bytes of data, I resolve();
            socket.once( "data", () => {
                resolve();
            } );

            socket.once( "error", err => reject( err ) );
        } );
    };

reconnect({host: localhost, port: 8080})
    .then(() => console.log("I made it!"));

为什么?

  1. 发电机有点矫枉过正。生成器可能具有有效的用例,但不在此处。使用它们会使principle of least astonishment失效,同时可以通过更简单的方法实现同样的效果。
  2. 延迟承诺是众所周知的anti-pattern。不,不。
  3. 使用setImmediate非常不必要。而不是要求循环执行立即运行代码,可以在大多数情况下使用循环(就像在这一个中)。
  4. 调用重新连接而不是连接将无效使调用者失去与重新连接调用的连接。当重新连接最终成功时,它将是另一个,并且不会通知原始请求的调用者。
  5. 我的解决方案解决了所有这些问题。

    但是,你的解决方案正在阻止!

    不,不是。它会是任何其他语言,但是在这里,因为我使用await运算符,我实际上允许Node继续执行循环。就像一个承诺。