"interval with timeout" 使用 Promises 的好模式是什么
What is a good pattern for "interval with timeout" using Promises
我正在编写一些代码来每隔 N 毫秒轮询一次资源,这应该会在 M 秒后超时。我希望尽可能多地使用 Bluebird 来承诺整个事情。到目前为止我想出的解决方案使用节点的间隔、可取消的蓝鸟承诺和蓝鸟的超时功能。
我想知道是否有更好的方法来处理 bluebird 和 promises 的超时间隔?主要是通过确保间隔在该点停止并且永远不会无限期地继续。
var Promise = require('bluebird');
function poll() {
var interval;
return new Promise(function(resolve, reject) {
// This interval never resolves. Actual implementation could resolve.
interval = setInterval(function() {
console.log('Polling...')
}, 1000).unref();
})
.cancellable()
.catch(function(e) {
console.log('poll error:', e.name);
clearInterval(interval);
// Bubble up error
throw e;
});
}
function pollOrTimeout() {
return poll()
.then(function() {
return Promise.resolve('finished');
})
.timeout(5000)
.catch(Promise.TimeoutError, function(e) {
return Promise.resolve('timed out');
})
.catch(function(e) {
console.log('Got some other error');
throw e;
});
}
return pollOrTimeout()
.then(function(result) {
console.log('Result:', result);
});
输出:
Polling...
Polling...
Polling...
Polling...
poll error: TimeoutError
Result: timed out
我会做这样的事情 -
function poll() {
return Promise.resolve().then(function() {
console.log('Polling...');
if (conditionA) {
return Promise.resolve();
} else if (conditionB) {
return Promise.reject("poll error");
} else {
return Promise.delay(1000).then(poll);
}
})
.cancellable()
}
还要注意Promise constructor anti-pattern
Rene Wooller 提出了一个非常好的观点:
Warning: unfortunately, recursion in javascript like this will eventually saturate the call stack and result in out of memory exceptions
即使没有异常,这也是浪费 space,异常的风险可能会导致轮询延迟过长。
我认为这很重要,所以更喜欢 setInterval:
var myPromise = new Promise((resolve, reject) => {
var id = window.setInterval(() => {
try {
if (conditionA) {
window.clearInterval(id);
resolve("conditionA");
} else if (conditionB) {
throw new Error("conditionB!");
}
} catch(e) {
window.clearInterval(id);
reject(e);
}
}, 1000);
});
有几个 npm 包可以满足这个要求,我最喜欢 promise-waitfor。它有 38 行长并且可以完成工作。
var myPromise = waitFor(() => {
if(conditionA) return true;
if(conditionB) throw new Error("conditionB!");
return false;
});
我正在编写一些代码来每隔 N 毫秒轮询一次资源,这应该会在 M 秒后超时。我希望尽可能多地使用 Bluebird 来承诺整个事情。到目前为止我想出的解决方案使用节点的间隔、可取消的蓝鸟承诺和蓝鸟的超时功能。
我想知道是否有更好的方法来处理 bluebird 和 promises 的超时间隔?主要是通过确保间隔在该点停止并且永远不会无限期地继续。
var Promise = require('bluebird');
function poll() {
var interval;
return new Promise(function(resolve, reject) {
// This interval never resolves. Actual implementation could resolve.
interval = setInterval(function() {
console.log('Polling...')
}, 1000).unref();
})
.cancellable()
.catch(function(e) {
console.log('poll error:', e.name);
clearInterval(interval);
// Bubble up error
throw e;
});
}
function pollOrTimeout() {
return poll()
.then(function() {
return Promise.resolve('finished');
})
.timeout(5000)
.catch(Promise.TimeoutError, function(e) {
return Promise.resolve('timed out');
})
.catch(function(e) {
console.log('Got some other error');
throw e;
});
}
return pollOrTimeout()
.then(function(result) {
console.log('Result:', result);
});
输出:
Polling...
Polling...
Polling...
Polling...
poll error: TimeoutError
Result: timed out
我会做这样的事情 -
function poll() {
return Promise.resolve().then(function() {
console.log('Polling...');
if (conditionA) {
return Promise.resolve();
} else if (conditionB) {
return Promise.reject("poll error");
} else {
return Promise.delay(1000).then(poll);
}
})
.cancellable()
}
还要注意Promise constructor anti-pattern
Rene Wooller 提出了一个非常好的观点:
Warning: unfortunately, recursion in javascript like this will eventually saturate the call stack and result in out of memory exceptions
即使没有异常,这也是浪费 space,异常的风险可能会导致轮询延迟过长。
我认为这很重要,所以更喜欢 setInterval:
var myPromise = new Promise((resolve, reject) => {
var id = window.setInterval(() => {
try {
if (conditionA) {
window.clearInterval(id);
resolve("conditionA");
} else if (conditionB) {
throw new Error("conditionB!");
}
} catch(e) {
window.clearInterval(id);
reject(e);
}
}, 1000);
});
有几个 npm 包可以满足这个要求,我最喜欢 promise-waitfor。它有 38 行长并且可以完成工作。
var myPromise = waitFor(() => {
if(conditionA) return true;
if(conditionB) throw new Error("conditionB!");
return false;
});