什么是使用承诺"interval with timeout"的好模式



我正在编写一些代码,每N毫秒对资源进行轮询,该轮询应该在M秒后超时。我希望整个事情是基于使用蓝鸟尽可能多的承诺。到目前为止,我提出的解决方案使用了node的interval、可取消的bluebird承诺和bluebird的超时函数。

我想知道是否有更好的方法来对蓝鸟和一般的承诺进行计时间隔?主要是通过确保间隔在某一点停止,而不是无限地继续。

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构造函数的反模式

Rene Wooller说得很好:

警告:不幸的是,像这样的javascript递归最终会使调用堆栈饱和,并导致内存不足的异常

即使它没有异常,这也是浪费空间,并且异常的风险可能会导致过长的轮询延迟。

我认为这很重要,所以我更喜欢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-wait。它有38行长,完成了任务。

var myPromise = waitFor(() => {
    if(conditionA) return true;
    if(conditionB) throw new Error("conditionB!");
    return false;
});

最新更新