使用取消方法

时间:2016-03-04 08:00:27

标签: javascript node.js promise es6-promise cancellation

我尝试编写一些代码,在启动一些可能长时间运行的异步活动后返回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,虽然我也希望在当前的浏览器中使用它。

3 个答案:

答案 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的未来版本中。