【问题标题】:Using a promise to implement a timeout - throw an error使用 Promise 实现超时 - 抛出错误
【发布时间】:2016-12-08 10:14:29
【问题描述】:

我正在尝试使用 promise 和 setTimeout 为异步函数实现超时。我想运行一个异步操作,如果它在一定时间内没有完成,就会抛出一个错误。目前,这就是我所拥有的:(其中一些在 stackoverflow 上找到)

function someOperation(cb) {
  setTimeout(function() {
    cb(null, 'Done');
  }, 2000);
}


var p = new Promise(function(resolve, reject) {
  setTimeout(function() {
    reject(new Error('Operation timed out'));
  }, 100);

  someOperation(function(err, res) {
    if (err) reject(err);
    else resolve(res);
  });

});

p.then(function(res) {
  console.log(res);
}, function(err) {
  console.log("Throwing error...")
  throw err;
});

但是抛出错误时程序并没有停止。谁能告诉我为什么,如果有更简单的方法可以做到这一点?我会非常感激。

编辑:现在尝试第一次使用 bluebird,它给出了 someOperationPromised.timeout 不是一个函数。我这样做对吗?

var Promise = require("bluebird");

function someOperation(cb) {
  setTimeout(function() {
    cb('', 'Done');
  }, 2000);
}

var someOperationPromised = Promise.promisify(someOperation);

someOperationPromised.timeout(1).then(function (){
  console.log("Finished!");
}).catch(Promise.TimeoutError, function (err) {
  throw err;
});

【问题讨论】:

  • "程序没有停止" - 你的意思是什么?您希望取消 2 秒的操作吗?不,你必须明确地这样做。
  • 您必须实际调用someOperationPromised(),并在其后加上括号。
  • " "程序没有停止" - 你的意思是什么?" 是一个非常活泼的问题。一旦 [[PromiseStatus]] 设置为 rejected 之后的决议不会对承诺状态产生任何影响。与此同时,您的someOperation 函数将运行,但是由于您需要解析它的结果并在当时的onfulfillment 回调中使用它,它不会产生任何结果,因为不会调用onfulfillment 回调。这就是事情在 Promise 中被取消的方式。

标签: javascript node.js promise cancellation


【解决方案1】:

不确定您使用的是什么承诺库,如果有的话。我可以建议Bluebird 吗?它比原生更快,并且有很多很棒的功能。他们之中?超时。

来自documentation

var Promise = require("bluebird");
var fs = Promise.promisifyAll(require('fs'));
fs.readFileAsync("huge-file.txt").timeout(100).then(function(fileContents) {

}).catch(Promise.TimeoutError, function(e) {
    console.log("could not read file within 100ms");
});

编辑:

你好!我花了一些时间整理这个,试图找出你的编辑为什么不起作用。我的目标是向您证明.timeout() 有效。此外,我想为您提供一个可行的解决方案,您可以使用 Bluebird 继续前进。

下面我包含一个我命名为takesFourSeconds 的函数。它返回一个承诺,将在 4 秒后解决。然后我打电话给takesFourSeconds 两次。我第一次使用超时来强制承诺链在超过 3 秒时拒绝。如果需要超过 5 秒,我会第二次强制它拒绝。

var Promise = require("bluebird");

function takesFourSeconds (){
    return new Promise((resolve, reject) => {
        setTimeout(function(){
            return resolve('hi');
        }, 4000);
    });
}

takesFourSeconds().timeout(3000).then(function(res) {
    console.log(res);
}).catch(Promise.TimeoutError, function(e) {
    console.log("promise took longer than 3 seconds");
});

takesFourSeconds().timeout(5000).then(function(res) {
    console.log(res);
}).catch(Promise.TimeoutError, function(e) {
    console.log("promise took longer than 5 seconds");
});

注意这会返回:

$ node index.js
promise took longer than 3 seconds
hi

正如预期的那样。

小注:

当创建一个返回 Promise 的函数时,你不必为你在 Promise 链中调用的每个函数都创建一个新的 Promise。只有第一个函数。

例如,如果我想在takesFourSeconds() 之后调用另一个函数,我可以这样写:

function myFunc(result){
  return result === 'hi' ? resolve('hey there') : reject('hi there');
}

然后:

takesFourSeconds()
  .then(myFunc) // myFunc will take in the resolved value of takesFourSeconds implicitly
  .then(result => console.log(result)
  .catch(error => console.log(error);

这应该输出:

"hey there"

你有它! Bluebird.js 中的超时。 :)

【讨论】:

  • 我确实做到了。我的回答有什么你不喜欢的吗?我向他展示了我如何知道如何解决他的问题。回答“有更简单的方法吗?”。
  • 嗯,也许,我觉得这个问题更多的是关于“有人能告诉我为什么吗?”
  • 是的,我没有触及那部分。 xD
  • 感谢您的回复。我正在尝试使用 bluebird 但出现错误,你会碰巧知道为什么吗?我已经更新了我原来的问题。
  • 我去看看。感谢您更新您的问题。 :)
猜你喜欢
  • 1970-01-01
  • 2017-11-23
  • 2017-06-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-05
  • 2018-11-27
  • 1970-01-01
相关资源
最近更新 更多