Javascript 如果未能及时完成,NodeJS超时承诺

Javascript 如果未能及时完成,NodeJS超时承诺,javascript,node.js,promise,settimeout,Javascript,Node.js,Promise,Settimeout,在一定时间后,我如何使承诺超时? 我知道Q有一个承诺超时,但我使用的是本机NodeJS承诺,它们没有.timeout函数 我是少了一个还是包装不同了 或者,下面的实现在不占用内存的情况下是否很好,实际工作是否如预期的那样 我还可以将它以某种方式进行全局包装,这样我就可以将它用于我创建的每个承诺,而不必重复setTimeout和clearTimeout代码 function run() { logger.info('DoNothingController working on proces

在一定时间后,我如何使承诺超时? 我知道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);
    });
}

谢谢

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

关于您的实现的问题可能更适合您,但请注意:

  • 你没有提供在承诺中实际做任何事情的方法,并且

  • setTimeout
    回调中不需要
    clearTimeout
    ,因为
    setTimeout
    调度一个一次性计时器

  • 因为承诺一旦被解决/拒绝就不能被解决/拒绝,所以你不需要检查

  • 因此,继续您的
    myPromise
    函数方法,可能是这样的:

    function myPromise(timeout, callback) {
        return new Promise((resolve, reject) => {
            // Set up the timeout
            const timer = setTimeout(() => {
                reject(new Error(`Promise timed out after ${timeout} ms`));
            }, timeout);
    
            // Set up the real work
            callback(
                (value) => {
                    clearTimeout(timer);
                    resolve(value);
                },
                (error) => {
                    clearTimeout(timer);
                    reject(error);
                }
            );
        });
    }
    
    myPromise(2000, (resolve, reject) => {
        // Real work is here
    });
    
    这样使用:

    function myPromise(timeout, callback) {
        return new Promise((resolve, reject) => {
            // Set up the timeout
            const timer = setTimeout(() => {
                reject(new Error(`Promise timed out after ${timeout} ms`));
            }, timeout);
    
            // Set up the real work
            callback(
                (value) => {
                    clearTimeout(timer);
                    resolve(value);
                },
                (error) => {
                    clearTimeout(timer);
                    reject(error);
                }
            );
        });
    }
    
    myPromise(2000, (resolve, reject) => {
        // Real work is here
    });
    
    (或者可能稍微不那么复杂,请参见下面的分隔符。)

    我会稍微关注语义不同的事实(没有
    new
    ,而您确实使用
    new
    Promise
    构造函数)。但更大的问题是,它假设您总是从头开始创建承诺,但您通常希望能够使用您已经拥有的承诺

    您可以通过子类化
    Promise
    来处理这两个问题:

    class MyPromise extends Promise {
        constructor(timeout, 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.
            const haveTimeout = typeof timeout === "number";
            const init = haveTimeout ? callback : timeout;
            super((resolve, reject) => {
                if (haveTimeout) {
                    const timer = setTimeout(() => {
                        reject(new Error(`Promise timed out after ${timeout}ms`));
                    }, timeout);
                    init(
                        (value) => {
                            clearTimeout(timer);
                            resolve(value);
                        },
                        (error) => {
                            clearTimeout(timer);
                            reject(error);
                        }
                    );
                } else {
                    init(resolve, reject);
                }
            });
        }
        // Pick your own name of course. (You could even override `resolve` itself
        // if you liked; just be sure to do the same arguments detection we do
        // above in the constructor, since you need to support the standard use of
        // `resolve`.)
        static resolveWithTimeout(timeout, x) {
            if (!x || typeof x.then !== "function") {
                // `x` isn't a thenable, no need for the timeout,
                // fulfill immediately
                return this.resolve(x);
            }
            return new this(timeout, x.then.bind(x));
        }
    }
    
    用法(如果构建新承诺):

    用法(如果使用您已有的承诺):

    现场示例:

    “严格使用”;
    类MyPromise扩展了Promise{
    构造函数(超时、回调){
    //我们需要支持无毫秒调用
    //值,因为各种Promise方法(`then`和
    //这样)在以下情况下正确调用子类构造函数
    //建立他们所回报的新承诺。
    const haveTimeout=typeof timeout==“number”;
    const init=haveTimeout?回调:超时;
    超级((解决、拒绝)=>{
    if(haveTimeout){
    常量计时器=设置超时(()=>{
    拒绝(新错误(`Promise timeout after${timeout}ms`);
    },超时);
    初始化(
    (值)=>{
    清除超时(计时器);
    决心(价值);
    },
    (错误)=>{
    清除超时(计时器);
    拒绝(错误);
    }
    );
    }否则{
    初始化(解决、拒绝);
    }
    });
    }
    //当然,选择你自己的名字。(你甚至可以覆盖'resolve'本身。)
    //如果您喜欢,请确保执行与我们相同的参数检测
    //在构造函数中,因为您需要支持
    //‘解决`。)
    静态resolveWithTimeout(超时,x){
    如果(!x | | typeof x.then!=“函数”){
    //'x'不是一个表,不需要超时,
    //立即履行
    返回此。解决(x);
    }
    返回新的this(超时,x.then.bind(x));
    }
    }
    //演示的一些功能
    const neverSettle=()=>新承诺(()=>{});
    const fulfillAfterDelay=(延迟,值)=>newpromise((解析)=>setTimeout(解析,延迟,值));
    const rejectAfterDelay=(延迟,错误)=>新承诺((解析,拒绝)=>设置超时(拒绝,延迟,错误));
    常量示例=[
    创建新Promise1()时的函数用法{
    log(“创建新承诺时显示超时”);
    const p=新承诺(100,(解决,拒绝)=>{
    //我们从不解析/拒绝,所以我们测试超时
    });
    返回p.then((值)=>{
    log(`completed:${value}`);
    })
    .catch((错误)=>{
    log(`Rejected:${error}`);
    });
    },
    创建新Promise2()时的函数用法{
    log(“显示超时前承诺何时履行”);
    const p=新承诺(100,(解决,拒绝)=>{
    setTimeout(解析,50,“工作”);
    });
    返回p.then((值)=>{
    log(`completed:${value}`);
    })
    .catch((错误)=>{
    log(`Rejected:${error}`);
    });
    },
    创建新Promise3()时的函数用法{
    log(“显示承诺在超时之前被拒绝的时间”);
    const p=新承诺(100,(解决,拒绝)=>{
    setTimeout(拒绝,50,新错误(“失败”);
    });
    返回p.then((值)=>{
    log(`completed:${value}`);
    })
    .catch((错误)=>{
    log(`Rejected:${error}`);
    });
    },
    函数用法(当您已准备好访问权限1时){
    log(“使用我们已有的承诺时显示超时”);
    返回MyPromise.resolveWithTimeout(100,neverSettle())
    。然后((值)=>{
    log(`completed:${value}`);
    })
    .catch((错误)=>{
    log(`Rejected:${error}`);
    });
    },
    函数用法(当您已准备好访问权限2时){
    log(“使用我们已有的承诺时显示履行”);
    返回MyPromise.resolveWithTimeout(100,fulfillAfterDelay(50,“已工作”))
    。然后((值)=>{
    log(`completed:${value}`);
    })
    .catch((错误)=>{
    log(`Rejected:${error}`);
    });
    },
    函数用法(当您已准备好访问权限3时){
    log(“显示拒绝
    
    var Promise = require('bluebird');
    var p = new Promise(function(reject, resolve) { /.../ });
    p.timeout(3000) //make the promise timeout after 3000 milliseconds
     .then(function(data) { /handle resolved promise/ })
     .catch(Promise.TimeoutError, function(error) { /handle timeout error/ })
     .catch(function(error) { /handle any other non-timeout errors/ });
    
    const withTimeout = (millis, promise) => {
        const timeout = new Promise((resolve, reject) =>
            setTimeout(
                () => reject(`Timed out after ${millis} ms.`),
                millis));
        return Promise.race([
            promise,
            timeout
        ]);
    };
    
    await withTimeout(5000, doSomethingAsync());
    
    const { TimeoutResolvePromise, TimeoutRejectPromise } = require('nodejs-promise-timeout');
    const TIMEOUT_DELAY = 2000;
    
    // This promise will reject after 2 seconds:
    let promise1 = new TimeoutRejectPromise(TIMEOUT_DELAY, (resolve, reject) => {
      // Do something useful here, then call resolve() or reject()
    });
    
    import {timeout} from 'utils-decorators';
    
    class SomeService {
    
       @timeout(3000)
       doSomeAsync(): Promise<any> {
        ....
       }
    }
    
    import {timeoutify} from 'utils-decorators';
    
    const withTimeout = timeoutify(originalFunc, 3000);
    
    
    const result = await withTimeout(() => doSomethingAsync(...args), 3000)();
    
    const result = await withTimeout(doSomethingAsync, 3000)(...args);
    
    const doSomethingAsyncWithTimeout = withTimeout(doSomethingAsync, 3000);
    const result = await doSomethingAsyncWithTimeout(...args);
    
    /**
     * returns a new function which calls the input function and "races" the result against a promise that throws an error on timeout.
     *
     * the result is:
     * - if your async fn takes longer than timeout ms, then an error will be thrown
     * - if your async fn executes faster than timeout ms, you'll get the normal response of the fn
     *
     * ### usage
     * ```ts
     * const result = await withTimeout(() => doSomethingAsync(...args), 3000);
     * ```
     * or
     * ```ts
     * const result = await withTimeout(doSomethingAsync, 3000)(...args);
     * ```
     * or even
     * ```ts
     * const doSomethingAsyncWithTimeout = withTimeout(doSomethingAsync, 3000);
     * const result = await doSomethingAsyncWithTimeout(...args);
     * ```
     */
    const withTimeout = <R, P extends any, T extends (...args: P[]) => Promise<R>>(logic: T, ms: number) => {
      return (...args: Parameters<T>) => {
        // create a promise that rejects in <ms> milliseconds; https://italonascimento.github.io/applying-a-timeout-to-your-promises/
        const timeout = new Promise((resolve, reject) => {
          const id = setTimeout(() => {
            clearTimeout(id);
            reject(new Error(`promise was timed out in ${ms} ms, by withTimeout`));
          }, ms); // tslint:disable-line align
        });
    
        // returns a "race" between our timeout and the function executed with the input params
        return Promise.race([
          logic(...args), // the wrapped fn, executed w/ the input params
          timeout, // the timeout
        ]) as Promise<R>;
      };
    };