Promise.some()超时?

时间:2016-06-27 20:19:56

标签: javascript node.js promise bluebird

用例 - 获取一堆网址并缓存结果。快速完成的(比如说500毫秒)会被合并到这个传递中,任何花费的时间都会超过仍然完成并保存到缓存,所以下一轮(在我们的应用程序中大约10分钟后)它们都在缓存中。

我希望能够执行Promise.someWithTimeout(promises, timeout)之类的操作,其结果是在超时到期之前完成的已解析值数组。 (Promise.some()非常靠近它需要计数而不是超时)

这样的东西
Promise.someWithTimeout([promises], <timeout value>)
.then((results) => {
  //stuff
})

每个承诺看起来像

return memcache.getAsync(keyFromUrl(url))
.then((cacheRes) => {
  if(cacheRes) return cacheRes;
  //not in cache go get it
  return rp(url)
  .then((rpRes) => {
    //Save to cache but don't wait for it to complete
    memcache.setAsync(keyFromUrl(url), rpRes, 86400).catch((e) => { /*error logging*/ }) 
    return rpRes;
  })
})

这个想法是,如果网址快速恢复我们使用它,如果我们保释需要更长时间但仍然缓存结果,所以下次通过我们拥有它。因此,rp()超时会比Promise.someWithTimeout()一个

更长

有没有人写过lib来做这个(我找不到一个),还是有更好的模式?我虽然将Promise.all().timeout().finally()用于将结果存入数组的承诺,但感觉不合理,我无法完全理解。

1 个答案:

答案 0 :(得分:3)

对于一次性编码,您可以启动两个单独的promise链并使用标志来查看是否已经发生超时:

var timedOut = false;
// your regular code
Promise.all(...).then(function() {
    // cache the result, even if it came in after the timeout

    if (!timedOut) {
       // if we didn't time out, then show the response
    }
});

Promise.delay(1000).then(function() {
    timedOut = true;
    // do whatever you want to do on the timeout
});

如果你想将这个功能打包到一个方法中,并且能够同时访问它超时的事实和即使在超时之后的最终结果(例如你可以缓存它们),那么你有解决一些包含多条信息的东西。这是通过使用可以包含多个信息的对象进行解析来允许访问超时和最终数据的一种方法。

Promise.someWithTimeout = function(promiseArray, cnt, timeout) {
    var pSome = Promise.some(promiseArray, cnt).then(function(results) {
        return {status: "done", results: results};
    });
    var pTimer = Promise.delay(cnt).then(function() {
        return {status: "timeout", promise: pSome}
    });
    return Promise.race([pSome, pTimer]);
}

// sample usage
Promise.someWithTimeout(arrayOfPromises, 3, 1000).then(function(result) {
    if (result.status === "timeout") {
        // we timed out
        // the result of the data is still coming when result.promise is resolved if you still want access to it later
        result.promise.then(function(results) {
            // can still get access to the eventual results here 
            // even though there was a timeout before they arrived
        }).catch(...);
    } else {
        // result.results is the array of results from Promise.some()
    }
});