2017-02-14 11 views
1

私はBluebirdの約束を学んでおり、私はもはやDeferred()を使用しないことを学んでいます。 以下のコードは100%正確かつ意図通りに動作します。 これは、Deferredソリューションを使用するのではなく、Bluebirdの約束を使用するコードをリファクタリングするための私の練習です。 私は約束について(正確に)違った考え方を学ぶためにしようとしているが、多くの試行の後、私はまだのDeferredの助けを借りずにここ以下、この特定の問題を解決する方法を見つけ出すことはできません。Bluebird Promisesを使用して、延期されたアンチパターンでこれを解決するにはどうすればよいですか?

アイデアはありますか?

1)あなたのコンソールでこのプログラムを実行します。ここでは

は、それを実行する方法です。これは、別のコンソールウィンドウにそれをもう一度実行後)ポート8080

2を使用するのWebSocketサーバーを起動します。その1は3の後に約束したプログラミングの3年間でポート8080

// Initialization stuff 
const WebSocket = require('ws'); 
var wsServer; 

// Main Program 
// ================================================================= 
tryCreateWebsocket().then(
    function(){ 
     console.log("Websocket succesfully initialized."); 
    }, 
    function(){ 
     console.log("Websocket startup has failed!"); 
    } 
); 
// ================================================================= 



// Helper function: Creating a websocket, with a port as parameter 
function createWebsocket(port){ 
    return new Promise(function(resolve, reject){ 

     wsServer = new WebSocket.Server({ 
      perMessageDeflate: false, 
      port: port 
     }); 

     wsServer.on("error", reject); 
     wsServer.on("listening", resolve); 
    }); 
} 


// Main function: I try to create a websocket on 5 different ports with a resursive function 
function tryCreateWebsocket(attempt, myMainDfd){ 

    if(typeof attempt === "undefined"){ 
     attempt = 1; 
     myMainDfd = deferred(); 
    } 

    var ports = [8080, 8080, 8080, 8081, 8082]; // In the 2nd client, this should fail until port 8081 
    var curPort = ports[attempt - 1]; 

    var maxAttempts = 5; 


    createWebsocket(curPort) 
     .then(
      function(){ 
       myMainDfd.resolve(); // Success 
      }, 
      function(err){ // Error, retry 
       if(attempt != maxAttempts){ 
        console.log("- attempt " + attempt + " failed. Retry"); 
        tryCreateWebsocket(++attempt, myMainDfd); 
       }else{ 
        myMainDfd.reject(); 
       } 
      } 
     ); 

    return myMainDfd.promise; 
} 


// Helper Function: I'm still using deferreds for now 
function deferred() { 
     var resolve, reject; 
     var promise = new Promise(function() { 
       resolve = arguments[0]; 
       reject = arguments[1]; 
     }); 
     return { 
       resolve: resolve, 
       reject: reject, 
       promise: promise 
     }; 
} 
+0

[this fiddle](https://jsfiddle.net/pk50ks04/)のようになりますか? –

+0

@JaromandaX - 今あなたのコメントに気づいた。それが動作するようには思えませんが、事実にもかかわらず、それは本当に短いときちんと見ている、私はそのことについて申し訳ありません:-) –

+0

を1つを考え出す苦労を持っています - 私は2つの小さなミスを犯し –

答えて

2

との試みが失敗した起動し、ポート8081を使用しますが、私は唯一の延期を使用すると、私のコードは単純に作られたものな状況を発見しました。私はそれがかなりまれな状況であるという結論に至りました。正しいテクニック(ここで連鎖を使用すること)を学ぶことによって、ほとんどの場合それらを回避し、かなり一般的なミス(エラーの伝播が不完全である、またはキャッチされていない例外など)が発生しにくい簡単なコードになります。この特定のケースで

、あなたは.then()ハンドラ内から新しい約束を返すことによって、以前の約束にあなたのその後の試みをチェーンすることができます。これにより、接続機能から約束を返すことができますが、将来の再試行が成功するか、再試行がなくなるまで、その約束を将来の試行(最終的な解決を抑えておく)に備えておいてください。

あなたはこのようにそれを行うことができます。 connect()機能の内部で何が起こるかを具体的に試してみてください。

function tryCreateWebsocket(){ 

    var attempt = 1; 
    var ports = [8080, 8080, 8080, 8081, 8082]; 
    var maxAttempts = ports.length; 

    function connect() { 
     var curPort = ports[attempt - 1]; 
     return createWebsocket(curPort).catch(function(err){ // Error, retry 
      if(attempt < maxAttempts){ 
       console.log("- attempt " + attempt + " failed. Retry"); 
       ++attempt; 

       // chain next attempt onto previous promise 
       return connect(); 
      } else { 
       // reject here with no more retries 
       throw new Error("max retry attempts exceeded without successful connection"); 
      } 
     }); 
    } 

    // start trying to connect, return a promise 
    // errors will be caught and subsequent retries will be chained 
    // onto this first promise until it either succeeds or runs out 
    // of retry attempts 
    return connect(); 
} 

// Main Program 
// ================================================================= 
tryCreateWebsocket().then(function(wsServer){ 
    console.log("Websocket succesfully initialized."); 
    // server instance is valid here, use it for further code 
},function(){ 
    console.log("Websocket startup has failed!"); 
}); 
// ================================================================= 



// Helper function: Creating a websocket, with a port as parameter 
function createWebsocket(port){ 
    return new Promise(function(resolve, reject){ 

     wsServer = new WebSocket.Server({ 
      perMessageDeflate: false, 
      port: port 
     }); 

     wsServer.on("error", reject); 
     wsServer.on("listening", function() { 
      resolve(wsServer); 
     }); 
    }); 
} 

注、私は返さ約束のwsServerインスタンス解決された値を作るためにデザインを変更しました。次に、より高いスコープの変数を設定するために副作用に頼っているわけではありません。解決した約束からそれを入手し、それが有効であることを知っている時点であなたが望む場所に保管することができます。

+0

ありがとう、私はここでかなりのことを学んでいます。私はエラーを投げて前に苦労していた、そして、私はその道を去った。しかし、今私はあなたがそれをやった方法を見る。私は今あなたのコードの原則を追加しました。 –

+0

私はそれがすべて今やっきりしていると思います。それはすべて美しく動作し、私はいくつかの重要な原則を学びました。私は答えとしてあなたのソリューションをマークしました、私はそれがここで正しく動作すると思います。(これは何年ものうちにこのウェブサイトに何かを投稿した初めてのことです) あなたのアドバイスのために多くのThx! –

+0

@johndoe - うん、それはここで動作する方法です。喜んで助けてください。 – jfriend00

0

は、ここで私が思いついた一つの可能​​な解決策です。どう思いますか?まだ2つの約束を使用しています(1つはcreateWebsocket関数に、もう1つはtryCreateWebsocket関数にあります)。

function tryCreateWebsocket(){ 

    var lstPorts = [8080, 8080, 8080, 8081, 8080]; 
    return new Promise(function(resolve, reject){ 

     function next(port) { 

      createWebsocket(port) 
       .then(
        resolve, 
        function(){ // Reject, but not until you've tried a little 
         console.log("Port "+port+" failed. I might try the next port."); 
         // rejected 
         if(lstPorts.length >= 1){ 
          next(lstPorts.shift()) 
         }else{ 
          reject(); // do reject 
         } 

        } 
       ); 
     } 

     next(lstPorts.shift()); // Start the loop 
    }); 
} 
+0

これは一般的に[promise anti-pattern](https://github.com/petkaantonov/bluebird/wiki/Promise-anti-patterns)とみなされ、手動で作成した別の約束で返すことのできる約束事を不必要に折り返します。これは、エラー処理やエラー伝播で間違いを犯すのはかなり簡単です。 FYI、いつでも '.then(解決) 'と表示されると、おそらく約束を返して、それを余分な約束事で包むのを避けることができました。それは、おそらくもっと良い方法があるというシグナルです。私の答えでチェーンを使用する方法を見て、それを別の約束で包むのを避けることができます。 – jfriend00

関連する問題