Как сделать обещание от setTimeout [дубликат]



этот вопрос уже есть ответ здесь:



это не проблема реального мира, я просто пытаюсь понять, как создаются обещания.



мне нужно понять, как сделать обещание для функции, которая ничего не возвращает, как setTimeout.



Предположим, у меня есть:



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

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


как мне создать обещание, что async может вернуться после setTimeout готов callback()?



я предполагал, что обертывание приведет меня куда-нибудь:



function setTimeoutReturnPromise(){

function promise(){}

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

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


return promise;
}


но я не могу думать дальше.

520   1  

1 ответ:

обновление (2017)

здесь в 2017 году обещания встроены в JavaScript, они были добавлены спецификацией ES2015 (polyfills доступны для устаревших сред, таких как IE8-IE11). Синтаксис, с которым они пошли, использует обратный вызов, который вы передаете в Promise конструктор (the Promiseисполнитель), который получает функции для разрешения/отклонения обещания в качестве аргументов.

во-первых, так как async теперь имеет значение в JavaScript (даже хотя это только ключевое слово в определенных контекстах), я собираюсь использовать later как имя функции, чтобы избежать путаницы.

Основная Задержка

используя родные обещания (или верный полифилл) это будет выглядеть так:

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

обратите внимание, что это предполагает версию setTimeout, что соответствует определение для браузеров здесь setTimeout не передает никаких аргументов для обратного вызова, если вы не даете их после интервала (это может не быть правдой в средах, отличных от браузера, и не было верно в Firefox, но теперь; это правда в Chrome и даже обратно на IE8).

основная задержка со значением

если вы хотите, чтобы ваша функция дополнительно передавала значение разрешения, в любом неопределенно-современном браузере, который позволяет вам давать дополнительные аргументы setTimeout после задержки, а затем передает их в обратный вызов при вызове, вы можете сделать это (текущий Firefox и Chrome; IE11+, предположительно Edge; не IE8 или IE9, понятия не имею о 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 + arrow, это может быть более кратким:

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

или даже

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

отменяемая задержка со значением

если вы хотите сделать возможным отменить тайм-аут, вы не можете просто вернуть обещание от later, потому что обещания не могут быть отменены.

но мы можем легко вернуть объект с 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);

оригинальный ответ от

обычно у вас будет библиотека обещаний (тот, который вы пишете сами, или один из нескольких там). Эта библиотека обычно будет иметь объект, который вы можете создать, а затем "разрешить", и этот объект будет иметь "обещание", которое вы можете получить от него.

затем later будет иметь тенденцию смотреть что-то вроде этого:

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

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

в комментарии к вопросу я спросил:

вы пытаетесь создать свою собственную библиотеку обещание?

и сказал

я не была, но теперь я думаю, что это на самом деле то, что я пытался понять. Вот как это сделает библиотека

чтобы помочь этому пониманию, вот очень простые пример, который не удаленно обещает-A уступчивый:Скопировать Видео

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

Comments

    Ничего не найдено.