使用蓝鸟承诺,如何解决与延期的反模式?

我正在学习蓝鸟承诺,我正试图学习不再使用任何延期()。 下面的代码正确运行100%并按预期运行。 但是,这里是对我重构代码的练习,以便正确使用Bluebird承诺,而不是使用Deferred解决scheme。 我试图学会以不同的方式(正确地)对Promise进行思考,但经过多次尝试,我仍然无法find如何在没有 Deferreds的帮助下解决这个特定问题的方法。

有没有人有一个想法?

这里是如何运行它:

1)在你的控制台运行这个程序。 它将启动将使用端口8080的websocket服务器。

2)然后在另一个控制台窗口中再次运行它。 那个将启动并使用端口8081 3端口8080失败后使用端口8081。

// 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 }; } 

在3年的承诺编程中,我只发现了一个使用延期的情况,使得我的代码更简单。 我已经得出结论,这是一个非常罕见的情况。 通过学习正确的技术(在这里使用链接),几乎总是可以避免它们,最终得到更简单的代码,而这些代码在相当常见的错误(例如不完整的错误传播或未捕获的exception)中的风险较小。

在这种情况下,你可以通过在.then()处理程序中返回一个新的promise来链接你的后续尝试。 这允许你从你的连接函数中返回一个承诺,但是保留这个承诺用于未来的尝试(保持它的最终parsing),直到将来的重试尝试成功或者你用完重试尝试。

你可以这样做。 特别试一试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); }); }); } 

请注意,我改变了devise,使wsServer实例返回的诺言的解决价值。 那么,你不是依靠副作用来设置更高范围的variables。 你可以从解决的承诺中得到它,并在你知道有效的时候把它存储在你想要的地方。

这是我想出的一个可能的解决scheme。 你怎么看? 它仍然使用总共2个promise(createWebsocket函数中的一个和下面的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 }); }