我正在学习蓝鸟的承诺,我试图学习不再使用任何Deferred()。 以下代码正确运行100%并按预期运行。 但是,对于我来说,重构代码以正确使用Bluebird承诺而不是使用延迟解决方案。 我试图学习以不同的方式(正确地)思考Promise,但经过多次尝试后,我仍然无法在 >> 的帮助下找出解决这个特殊问题的方法。
有没有人有想法?
以下是如何运行它:
1)在您的控制台中运行此程序。它将启动一个将使用端口8080的websocket服务器。
2)然后在另一个控制台窗口中再次运行它。在尝试使用端口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
};
}
答案 0 :(得分:2)
在3年的承诺编程中,我只发现了一种使用延迟使我的代码更简单的情况。我得出的结论是,这种情况非常罕见。通过学习正确的技术(在这里使用链接),几乎总能避免它们,并最终得到更简单的代码,这些代码具有相对常见错误的风险较小(例如不完整的错误传播或未捕获的异常)。
在这种特殊情况下,您可以通过从.then()
处理程序中返回新的承诺,将后续尝试链接到上一个承诺。这允许您从connect函数返回一个promise,但是保留该promise以用于将来的尝试(阻止其最终解决方案),直到将来的某些重试尝试成功或者您的重试尝试用完为止。
你可以这样做。特别尝试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
实例成为返回的promise的已解析值。然后,您不依赖于副作用来设置更高范围的变量。您可以从已解决的承诺中获取它,并在您知道它有效时将其存储在您想要的位置。
答案 1 :(得分:0)
这是我提出的一种可能的解决方案。你怎么看?它仍然使用总共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
});
}