Promise.some() 超时?

问题描述 投票:0回答:1

用例 - 获取一堆 url 并缓存结果。快速完成的(例如 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;
  })
})

我们的想法是,如果 url 返回得很快,我们就使用它,如果需要更长的时间,我们就放弃但仍然缓存结果,这样下次我们就可以得到它。因此

rp()
超时会比
Promise.someWithTimeout()
超时长得多

有人写过一个库来做到这一点(我找不到),或者有更好的模式吗?我虽然考虑使用

Promise.all().timeout().finally()
并承诺将其结果存储到数组中,但感觉不对,因为我无法完全确定原因。

javascript node.js promise bluebird
1个回答
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(timeout).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()
    }
});

© www.soinside.com 2019 - 2024. All rights reserved.