我尝试编写一些代码,在启动一些可能长时间运行的异步活动后返回ES6承诺。但是,我希望有可能取消该活动,所以我想通过“取消”来增强我的承诺。方法
sscce说明了我要做的事情如下:
function TimerPromise(timeInterval) {
var timer;
var p = new Promise(
function(resolve,reject) {
timer = setTimeout(
function() {
resolve(true);
},
timeInterval
);
}
);
p.cancel = function() {
clearTimeout(timer);
};
console.log("p.cancel is ",p.cancel);
return p;
}
var t = TimerPromise(2000).then(function(res) { console.log("Result is ",res); });
t.cancel();
在示例中,TimerPromise只设置一个计时器来模拟长时间运行的异步活动。
这是我在运行时获得的:
$ node test.js
p.cancel is function () {
timer.clearTimeout();
}
/home/harmic/js/src/test.js:28
t.cancel();
^
TypeError: t.cancel is not a function
at Object.<anonymous> (/home/harmic/js/src/test.js:28:3)
at Module._compile (module.js:413:34)
at Object.Module._extensions..js (module.js:422:10)
at Module.load (module.js:357:32)
at Function.Module._load (module.js:314:12)
at Function.Module.runMain (module.js:447:10)
at startup (node.js:141:18)
at node.js:933:3
出于某种原因,我添加到promise中的cancel方法在离开函数后就消失了!
我有什么理由不能为ES6 Promise添加属性或方法吗?或者这是V8实施Promises的一些特点吗?
对于奖励积分 - 如果调用取消方法,我希望能够拒绝承诺,如下所示:
p.cancel = function() {
timer.clearTimeout();
reject(new Error("Request Cancelled"));
};
但是,我无法访问Promise执行程序之外的拒绝功能,而在Promise执行程序内部我无法访问承诺本身(或者我可以吗?)所以我无法在那里增加Promise。
这样做有什么明智的模式吗?
注意:我知道Bluebird提供了可取消的承诺作为扩展名。我希望使用ES6原生承诺来实现这一点。
我正在使用node.js 0.12,虽然我也希望在当前的浏览器中使用它。
答案 0 :(得分:6)
问题是调用then
将返回一个新的promise对象,因此你将使用cancel方法丢失对你的promise的引用。
function TimerPromise(timeInterval) {
var timer;
var p = new Promise(
function(resolve, reject) {
timer = setTimeout(
function() {
resolve(true);
},
timeInterval
);
}
);
p.cancel = function() {
clearTimeout(timer);
};
console.log("p.cancel is ", p.cancel);
return p;
}
var t = TimerPromise(2000);
t.then(function(res) {
console.log("Result is ", res);
});
t.cancel();
答案 1 :(得分:2)
除了Arun的回答,你可以通过引用它来解决var timer;
var reject;
var p = new Promise(
function(resolve, _reject) {
reject = _reject;
timer = setTimeout(
function() {
resolve(true);
},
timeInterval
);
}
);
p.cancel = function() {
clearTimeout(timer);
reject(new Error("Request Cancelled"));
};
不在范围内的问题,这是我的范围:
server {
server_name example.com;
...
}
server {
server_name ~^(?<subdomain>.+)\.example\.com$;
#you can use $subdomain in configuration
#root /var/www/example.com/$subdomain;
...
}
答案 2 :(得分:2)
我不明白为什么你需要考虑“取消”这个承诺。相反,您可以考虑提供拒绝的接口。您无需担心取消计时器,因为如果已经手动拒绝了承诺,那么即使计时器关闭并且resolve
被调用,它也不起作用。
function TimerPromise(timeInterval) {
var _reject;
var p = new Promise(function(resolve, reject) {
// Remember reject callback in outside scope.
_reject = reject;
setTimeout(() => resolve(true), timeInterval);
});
// Attach reject callback to promise to let it be invocable from outside.
p.reject= _reject();
return p;
}
但是,即使执行此操作,您也无法从下游承诺取消上游承诺,因为下游承诺不知道它的上游是什么。你必须这样做:
var t1 = TimerPromise(2000);
var t2 = t1.then(function(res) { console.log("Result is ", res); });
t1.reject();
与承诺相关的术语“取消”具有不同的,更复杂的含义,我不会在此处讨论。一些图书馆提供该功能;本机承诺没有,尽管正在讨论如何将它们添加到ES的未来版本中。