How to make a promise from setTimeout

This question already has an answer here:

  • How do I convert an existing callback API to promises? 17 answers

  • Update (2017)

    Here in 2017, Promises are built into JavaScript, they were added by the ES2015 spec (polyfills are available for outdated environments like IE8-IE11). The syntax they went with uses a callback you pass into the Promise constructor (the Promise executor) which receives the functions for resolving/rejecting the promise as arguments.

    First, since async now has a meaning in JavaScript (even though it's only a keyword in certain contexts), I'm going to use later as the name of the function to avoid confusion.

    Basic Delay

    Using native promises (or a faithful polyfill) it would look like this:

    function later(delay) {
        return new Promise(function(resolve) {
            setTimeout(resolve, delay);
        });
    }
    

    Note that that assumes a version of setTimeout that's compliant with the definition for browsers where setTimeout doesn't pass any arguments to the callback unless you give them after the interval (this may not be true in non-browser environments, and didn't used to be true on Firefox, but is now; it's true on Chrome and even back on IE8).

    Basic Delay with Value

    If you want your function to optionally pass a resolution value, on any vaguely-modern browser that allows you to give extra arguments to setTimeout after the delay and then passes those to the callback when called, you can do this (current Firefox and Chrome; IE11+, presumably Edge; not IE8 or IE9, no idea about IE10):

    function later(delay, value) {
        return new Promise(function(resolve) {
            setTimeout(resolve, delay, value); // Note the order, `delay` before `value`
            /* Or for outdated browsers that don't support doing that:
            setTimeout(function() {
                resolve(value);
            }, delay);
            Or alternately:
            setTimeout(resolve.bind(null, value), delay);
            */
        });
    }
    

    If you're using ES2015+ arrow functions, that can be more concise:

    function later(delay, value) {
        return new Promise(resolve => setTimeout(resolve, delay, value));
    }
    

    or even

    const later = (delay, value) =>
        new Promise(resolve => setTimeout(resolve, delay, value));
    

    Cancellable Delay with Value

    If you want to make it possible to cancel the timeout, you can't just return a promise from later , because promises can't be cancelled.

    But we can easily return an object with a cancel method and an accessor for the promise, and reject the promise on cancel:

    const later = (delay, value) => {
        let timer = 0;
        let reject = null;
        const promise = new Promise((resolve, _reject) => {
            reject = _reject;
            timer = setTimeout(resolve, delay, value);
        });
        return {
            get promise() { return promise; },
            cancel() {
                if (timer) {
                    clearTimeout(timer);
                    timer = 0;
                    reject();
                    reject = null;
                }
            }
        };
    };
    

    Live Example:

    const later = (delay, value) => {
        let timer = 0;
        let reject = null;
        const promise = new Promise((resolve, _reject) => {
            reject = _reject;
            timer = setTimeout(resolve, delay, value);
        });
        return {
            get promise() { return promise; },
            cancel() {
                if (timer) {
                    clearTimeout(timer);
                    timer = 0;
                    reject();
                    reject = null;
                }
            }
        };
    };
    
    const l1 = later(100, "l1");
    l1.promise
      .then(msg => { console.log(msg); })
      .catch(() => { console.log("l1 cancelled"); });
    
    const l2 = later(200, "l2");
    l2.promise
      .then(msg => { console.log(msg); })
      .catch(() => { console.log("l2 cancelled"); });
    setTimeout(() => {
      l2.cancel();
    }, 150);
    链接地址: http://www.djcxy.com/p/55510.html

    上一篇: 如何提升这个功能

    下一篇: 如何从setTimeout做出承诺