如何从setTimeout做出承诺 [英] How to make a promise from setTimeout

查看:78
本文介绍了如何从setTimeout做出承诺的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这不是一个现实世界的问题,我只是想了解如何创建承诺。

This is not a realworld problem, I'm just trying to understand how promises are created.

我需要了解如何为一个函数做出承诺什么都不返回,比如setTimeout。

I need to understand how to make a promise for a function that returns nothing, like setTimeout.

假设我有:

function async(callback){ 
    setTimeout(function(){
        callback();
    }, 5000);
}

async(function(){
    console.log('async called back');
});

如何创建 async 的承诺 setTimeout 准备好回调()

How do I create a promise that async can return after the setTimeout is ready to callback()?

我认为包装它会带我到某个地方:

I supposed wrapping it would take me somewhere:

function setTimeoutReturnPromise(){

    function promise(){}

    promise.prototype.then = function() {
        console.log('timed out');
    };

    setTimeout(function(){
        return ???
    },2000);


    return promise;
}

但我想不到这一点。

推荐答案

更新(2017)



2017年,Promises内置于JavaScript中,添加了它们通过ES2015规范(polyfills可用于过时的环境,如IE8-IE11)。他们使用的语法使用您传递到 Promise 构造函数的回调( Promise executor )接收解析/拒绝承诺作为参数的函数。

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.

首先,因为 async 现在在JavaScript中有意义(甚至虽然它只是某些上下文中的关键字),但我将稍后使用 作为函数的名称以避免混淆。

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.

使用原生承诺(或忠实的polyfill),它看起来像这样:

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

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

请注意,假设版本为 setTimeout 符合浏览器的定义,其中 setTimeout 除非你在间隔之后给出它们,否则不会将任何参数传递给回调(在非浏览器环境中可能不是这样,并且在Firefox上并不常见) ,但现在;它在Chrome上是真的,甚至回到IE8上。)

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).

如果你希望你的函数可选地传递一个分辨率值,在任何模糊的现代浏览器上允许你在延迟后给 setTimeout 提供额外的参数,然后将它们传递给回调在调用时,你可以这样做(当前的Firefox和Chrome; IE11 +,可能是Edge; 不是 IE8或IE9,不知道IE10):

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

如果你正在使用ES2015 +箭头功能,那可以更简洁:

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

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

甚至

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.

但是我们可以使用 cancel 方法和承诺的访问者轻松返回一个对象,并在取消时拒绝承诺:

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

实例:

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

通常你会有一个诺言库(你自己写的,或者其中一个)。该库通常会有一个您可以创建并稍后解析的对象,并且该对象将具有您可以从中获得的承诺。

Usually you'll have a promise library (one you write yourself, or one of the several out there). That library will usually have an object that you can create and later "resolve," and that object will have a "promise" you can get from it.

然后稍后会看起来像这样:

function later() {
    var p = new PromiseThingy();
    setTimeout(function() {
        p.resolve();
    }, 2000);

    return p.promise(); // Note we're not returning `p` directly
}






在对这个问题的评论中,我问:


In a comment on the question, I asked:


您是否正在尝试创建自己的承诺库?

Are you trying to create your own promise library?

你说


我不是'但我想现在这实际上是我想要了解的。库如何做到这一点

I wasn't but I guess now that's actually what I was trying to understand. That how a library would do it

为了帮助理解,这里有一个非常非常基本的示例,不符合Promises-A标准:实时复制

To aid that understanding, here's a very very basic example, which isn't remotely Promises-A compliant: Live Copy

<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>Very basic promises</title>
</head>
<body>
  <script>
    (function() {

      // ==== Very basic promise implementation, not remotely Promises-A compliant, just a very basic example
      var PromiseThingy = (function() {

        // Internal - trigger a callback
        function triggerCallback(callback, promise) {
          try {
            callback(promise.resolvedValue);
          }
          catch (e) {
          }
        }

        // The internal promise constructor, we don't share this
        function Promise() {
          this.callbacks = [];
        }

        // Register a 'then' callback
        Promise.prototype.then = function(callback) {
          var thispromise = this;

          if (!this.resolved) {
            // Not resolved yet, remember the callback
            this.callbacks.push(callback);
          }
          else {
            // Resolved; trigger callback right away, but always async
            setTimeout(function() {
              triggerCallback(callback, thispromise);
            }, 0);
          }
          return this;
        };

        // Our public constructor for PromiseThingys
        function PromiseThingy() {
          this.p = new Promise();
        }

        // Resolve our underlying promise
        PromiseThingy.prototype.resolve = function(value) {
          var n;

          if (!this.p.resolved) {
            this.p.resolved = true;
            this.p.resolvedValue = value;
            for (n = 0; n < this.p.callbacks.length; ++n) {
              triggerCallback(this.p.callbacks[n], this.p);
            }
          }
        };

        // Get our underlying promise
        PromiseThingy.prototype.promise = function() {
          return this.p;
        };

        // Export public
        return PromiseThingy;
      })();

      // ==== Using it

      function later() {
        var p = new PromiseThingy();
        setTimeout(function() {
          p.resolve();
        }, 2000);

        return p.promise(); // Note we're not returning `p` directly
      }

      display("Start " + Date.now());
      later().then(function() {
        display("Done1 " + Date.now());
      }).then(function() {
        display("Done2 " + Date.now());
      });

      function display(msg) {
        var p = document.createElement('p');
        p.innerHTML = String(msg);
        document.body.appendChild(p);
      }
    })();
  </script>
</body>
</html>

这篇关于如何从setTimeout做出承诺的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆