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

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

问题描述

这不是现实世界的问题,我只是想了解 Promise 是如何创建的.

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 准备好 callback() 后返回的承诺?

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 年,Promise 被内置到 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 中有一个含义(即使它在某些上下文中只是一个关键字),我将使用 later 作为函数的名称以避免混淆.

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

具有价值的可取消延迟

如果你想让取消超时成为可能,你不能只从later返回一个promise,因为promise不能被取消.

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

通常你会有一个 promise 库(一个你自己写的,或者其他几个之一).该库通常会有一个您可以创建并在以后解析"的对象,并且该对象会有一个您可以从中获得的承诺".

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天全站免登陆