当前位置: 首页 > 知识库问答 >
问题:

NodeJS在无法及时完成promise时超时

乌骏
2023-03-14

我怎样才能在一定的时间后超时一个承诺?我知道Q有一个承诺超时,但我使用的是原生NodeJS承诺,它们没有.timeout函数。

是我少了一个还是它的包装方式不同?

或者,下面的实现在不占用内存方面是否很好,实际上是按照预期工作的?

同样,我可以使它以某种方式进行全局包装,以便我可以在创建的每个承诺中使用它,而不必重复setTimeout和clearTimeout代码吗?

function run() {
    logger.info('DoNothingController working on process id {0}...'.format(process.pid));

    myPromise(4000)
        .then(function() {
            logger.info('Successful!');
        })
        .catch(function(error) {
            logger.error('Failed! ' + error);
        });
}

function myPromise(ms) {
    return new Promise(function(resolve, reject) {
        var hasValueReturned;
        var promiseTimeout = setTimeout(function() {
            if (!hasValueReturned) {
                reject('Promise timed out after ' + ms + ' ms');
            }
        }, ms);

        // Do something, for example for testing purposes
        setTimeout(function() {
            resolve();
            clearTimeout(promiseTimeout);
        }, ms - 2000);
    });
}

谢谢!

共有2个答案

太叔高义
2023-03-14

虽然可能不支持承诺超时,但您可以赛跑承诺:

null

var race = Promise.race([
  new Promise(function(resolve){
    setTimeout(function() { resolve('I did it'); }, 1000);
  }),
  new Promise(function(resolve, reject){
    setTimeout(function() { reject('Timed out'); }, 800);
  })
]);

race.then(function(data){
  console.log(data);
  }).catch(function(e){
  console.log(e);
  });
屈翰飞
2023-03-14

本机JavaScript承诺没有任何超时机制。

关于您的实现的问题可能更适合http://codereview.stackExchange.com,但需要注意以下几点:

>

  • 您没有提供在承诺中实际执行任何操作的方法,并且

    settimeout回调中不需要cleartimeout,因为settimeout会安排一个一次性计时器。

    既然一个承诺一旦被解决/拒绝就不能被解决/拒绝,那么你就不需要那张支票了。

    所以也许有这样的东西:

    function myPromise(ms, callback) {
        return new Promise(function(resolve, reject) {
            // Set up the real work
            callback(resolve, reject);
    
            // Set up the timeout
            setTimeout(function() {
                reject('Promise timed out after ' + ms + ' ms');
            }, ms);
        });
    }
    

    这样使用:

    myPromise(2000, function(resolve, reject) {
        // Real work is here
    });
    

    (或者您可能希望它更复杂一些,请参阅下面一行的update。)

    我会稍微担心语义略有不同(没有new,而您确实将newpromise构造函数一起使用),因此可以对其进行调整。

    当然,另一个问题是,大多数时候,你不想构建新的承诺,所以不能使用上面的内容。大多数情况下,您已经有了一个承诺(前一个then调用的结果,等等)。但是对于真正构建一个新的承诺的情况,您可以使用类似于上面的东西。

    您可以通过子类化promise来处理new事件:

    class MyPromise extends Promise {
        constructor(ms, callback) {
            // We need to support being called with no milliseconds
            // value, because the various Promise methods (`then` and
            // such) correctly call the subclass constructor when
            // building the new promises they return.
            // This code to do it is ugly, could use some love, but it
            // gives you the idea.
            let haveTimeout = typeof ms === "number" && typeof callback === "function";
            let init = haveTimeout ? callback : ms;
            super((resolve, reject) => {
                init(resolve, reject);
                if (haveTimeout) {
                    setTimeout(() => {
                        reject("Timed out");
                    }, ms);
                }
            });
        }
    }
    

    用法:

    let p = new MyPromise(300, function(resolve, reject) {
        // ...
    });
    p.then(result => {
    })
    .catch(error => {
    });
    

    现场示例:

    null

    // Uses var instead of let and non-arrow functions to try to be
    // compatible with browsers that aren't quite fully ES6 yet, but
    // do have promises...
    (function() {
        "use strict";
        
        class MyPromise extends Promise {
            constructor(ms, callback) {
                var haveTimeout = typeof ms === "number" && typeof callback === "function";
                var init = haveTimeout ? callback : ms;
                super(function(resolve, reject) {
                    init(resolve, reject);
                    if (haveTimeout) {
            	        setTimeout(function() {
        	                reject("Timed out");
    	                }, ms);
                    }
                });
            }
        }
        
        var p = new MyPromise(100, function(resolve, reject) {
            // We never resolve/reject, so we test the timeout
        });
        p.then(function(result) {
        	snippet.log("Resolved: " + result);
        }).catch(function(reject) {
            snippet.log("Rejected: " + reject);
        });
    })();
    <!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
    <script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

  •  类似资料:
    • 问题内容: 一定时间后如何使承诺超时?我知道Q有一个Promise超时,但是我使用的是本机NodeJS Promise,它们没有.timeout函数。 我是否想念一个或包裹不同的包裹? 或者,下面的实现在不占用内存的情况下是否很好,实际上按预期方式工作? 还可以以某种方式将其包装到全局中,以便将其用于我创建的每个promise,而不必重复setTimeout和clearTimeout代码吗? 谢谢

    • 我正在Eclipse中使用Java运行selenium RC。我遇到的问题是selenium.click命令。我点击的链接加载一个新页面。有时需要5秒,有时需要2-3分钟。每次我看到页面加载时,在我的测试失败后,我立即得到消息“Timed out waiting for action to finish”。 我尝试使用Selenium.IsElementPresent检查正在加载的页面。但是,当我

    • 现在我想让所有的期货最多等待n秒,直到全部完成。我知道我可以调用,但是如果我在循环中对我的所有期货顺序地调用它,则超时开始增加。伪代码: 块会出现超时,直到结果就绪。因此,如果第一个在超时之前完成,第二个也在超时之前完成,依此类推,则整个执行时间最多为而不是。 因此,我正在寻找一个方法,它接受的列表和一个超时,并行运行所有的结果,然后返回一个未来结果的集合。有什么想法吗?

    • 我正在使用executorservice,每个webservice调用都会产生大约9-10个可调用任务,并提交给executorservice线程池。线程池大小为100的应用程序只有一个executorService。当我提交调用时,我有一个2 For循环。外部循环运行到指定的超时期满或完成的散列集大小==提交的任务大小;内部循环将遍历调用项,如果isDone()==true,则将这些调用项收集到

    • 我是新的完全未来。我试图为元素列表(即参数)调用并行方法,然后将结果组合起来创建最终响应。我还试图设置50毫秒的超时,以便如果调用不返回50毫秒,我将返回默认值。 到目前为止,我已经尝试过: 但我一直得到错误说: 有人能告诉我我在这里做错了什么吗?如果我走错了方向,请纠正我。 谢谢

    • 问题内容: 我有一个脚本,该脚本遍历包含要访问的URL:s并截取其屏幕截图的文本文件。 所有这一切都完成且简单。该脚本会初始化一个类,该类在运行时会创建列表中每个站点的屏幕快照。某些站点的加载时间非常非常长,而某些站点可能根本无法加载。因此,我想将函数包装在一个超时脚本中,以使该函数在10秒内无法完成时返回。 我对最简单的解决方案感到满意,也许设置一个异步计时器,无论函数内部实际发生什么,该计时器