当前位置: 首页 > 面试题库 >

如果未能及时完成,NodeJS将超时

阎承嗣
2023-03-14
问题内容

一定时间后如何使承诺超时?我知道Q有一个Promise超时,但是我使用的是本机NodeJS Promise,它们没有.timeout函数。

我是否想念一个或包裹不同的包裹?

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

还可以以某种方式将其包装到全局中,以便将其用于我创建的每个promise,而不必重复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);
    });
}

谢谢!


问题答案:

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

有关您的实现的问题可能更适合http://codereview.stackexchange.com,但有几点注意事项:

  1. 您没有提供在诺言中实际做任何事情的方法,并且

  2. 由于计划了一次计时器,因此不需要clearTimeoutsetTimeout回调中进行setTimeout

  3. 由于承诺一旦被解决/被拒绝,就无法被解决/被拒绝,因此您不需要进行检查。

所以也许遵循以下思路:

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
});

(或者您 可能 希望它稍微复杂一些,请参见下面的更新。)

我会稍微担心以下事实,即语义会稍有不同(no new,而您确实使用newPromise构造函数),因此可以进行调整。

当然,另一个问题是,在大多数情况下,您不想构建新的Promise,因此无法使用以上内容。大多数时候,您已经有一个承诺(上一次then通话的结果,等等)。但是,对于真正要构建新承诺的情况,可以使用上述类似方法。

您可以new通过子类化处理Promise

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 => {
});

现场示例:

// 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>

reject计时器到期时,即使回调调用resolvereject第一次调用,这两者都将调用。这很好,承诺的结算状态不能一旦它的设置改变,该规范定义来电resolvereject上一个已经解决的不产生错误的DO-
空话的承诺。

但是,如果麻烦您了,您可以把resolve和包装起来reject。这里的myPromise这样做的方式:

function myPromise(ms, callback) {
    return new Promise(function(resolve, reject) {
        // Set up the timeout
        let timer = setTimeout(function() {
            reject('Promise timed out after ' + ms + ' ms');
        }, ms);
        let cancelTimer = _ => {
            if (timer) {
                clearTimeout(timer);
                timer = 0;
            }
        };

        // Set up the real work
        callback(
            value => {
                cancelTimer();
                resolve(value);
            },
            error => {
                cancelTimer();
                reject(error);
            }
        );
    });
}

您可以旋转约18种不同的方式,但是基本概念是,resolve并且reject我们通过收到的promise执行程序是清除计时器的包装器。

但是 ,这会创建不需要的函数和额外的函数调用。规范明确了已解决诺言时的解决功能。他们很早就退出了。



 类似资料:
  • 我怎样才能在一定的时间后超时一个承诺?我知道Q有一个承诺超时,但我使用的是原生NodeJS承诺,它们没有.timeout函数。 是我少了一个还是它的包装方式不同? 或者,下面的实现在不占用内存方面是否很好,实际上是按照预期工作的? 同样,我可以使它以某种方式进行全局包装,以便我可以在创建的每个承诺中使用它,而不必重复setTimeout和clearTimeout代码吗? 谢谢!

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

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

  • 我想有一个清单的comletablefutures我想等待。带有以下代码。 问题是,在所有的期货,其中一些可以是缓慢的,我想在到期时间后,get方法返回与所有完成的结果。有办法做到这一点吗? 多谢.

  • 我正在使用Java8,我想知道对3个异步作业强制超时的推荐方法,我将执行异步并从未来检索结果。请注意,所有3个作业的超时是相同的。如果超出时间限制,我还想取消作业。 我在想这样的事情: 像这样的东西有用吗?有更好的方法吗? 如何正确地取消未来?Javadoc说,线程不能被中断?所以,如果我取消一个未来,并调用,我会立即得到结果,因为线程不会被中断吗? 在等待结束后,是否建议使用run()或get(

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