使用 Bluebird Promises,如何使用延迟反模式解决这个问题?
Using Bluebird Promises, how to solve this with the deferred anti-pattern?
我正在学习 Bluebird promises,我正在尝试学习不再使用任何 Deferred()。
下面的代码 运行s 100% 正确且符合预期。
但这是我重构代码以正确使用 Bluebird promises 而不是使用 Deferred 解决方案的练习。
我正在尝试学习以不同的方式(正确地)思考 Promises,但经过多次尝试后,我仍然无法弄清楚如何在下面没有 Deferreds 的帮助下解决这个特定问题。
有人知道吗?
运行 方法如下:
1) 运行 这个程序在你的控制台中。它将启动一个使用端口 8080 的 websocket 服务器。
2) 然后 运行 在另一个控制台中第二次 window。在尝试使用端口 8080 失败 3 次后,它将启动并使用端口 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 年的 promises 编程中,我只发现一种情况是使用 deferred 使我的代码更简单。我得出的结论是,这是一种非常罕见的情况。通过学习正确的技术(在这里使用链接),几乎总是可以避免它们并最终得到更简单的代码,这些代码更容易出现相当常见的错误(例如不完整的错误传播或未捕获的异常)。
在这种特殊情况下,您可以通过 return 从 .then()
处理程序中创建一个新承诺,将后续尝试链接到先前的承诺上。这允许您 return 来自连接函数的承诺,但在未来的尝试中保持该承诺(推迟其最终解决方案),直到未来的某些重试尝试成功或直到您 运行 重试失败。
你可以这样做。特别尝试 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
实例成为 returned 承诺的解析值。然后,您不依赖于副作用来设置更高范围的变量。您可以从已解决的承诺中获取它,并在您知道它有效时将其存储在您想要的位置。
这是我想到的一种可能的解决方案。你怎么看?它仍然总共使用了 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
});
}
我正在学习 Bluebird promises,我正在尝试学习不再使用任何 Deferred()。 下面的代码 运行s 100% 正确且符合预期。 但这是我重构代码以正确使用 Bluebird promises 而不是使用 Deferred 解决方案的练习。 我正在尝试学习以不同的方式(正确地)思考 Promises,但经过多次尝试后,我仍然无法弄清楚如何在下面没有 Deferreds 的帮助下解决这个特定问题。
有人知道吗?
运行 方法如下:
1) 运行 这个程序在你的控制台中。它将启动一个使用端口 8080 的 websocket 服务器。
2) 然后 运行 在另一个控制台中第二次 window。在尝试使用端口 8080 失败 3 次后,它将启动并使用端口 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 年的 promises 编程中,我只发现一种情况是使用 deferred 使我的代码更简单。我得出的结论是,这是一种非常罕见的情况。通过学习正确的技术(在这里使用链接),几乎总是可以避免它们并最终得到更简单的代码,这些代码更容易出现相当常见的错误(例如不完整的错误传播或未捕获的异常)。
在这种特殊情况下,您可以通过 return 从 .then()
处理程序中创建一个新承诺,将后续尝试链接到先前的承诺上。这允许您 return 来自连接函数的承诺,但在未来的尝试中保持该承诺(推迟其最终解决方案),直到未来的某些重试尝试成功或直到您 运行 重试失败。
你可以这样做。特别尝试 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
实例成为 returned 承诺的解析值。然后,您不依赖于副作用来设置更高范围的变量。您可以从已解决的承诺中获取它,并在您知道它有效时将其存储在您想要的位置。
这是我想到的一种可能的解决方案。你怎么看?它仍然总共使用了 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
});
}