webentwicklung-frage-antwort-db.com.de

Gibt es eine Version von setTimeout, die ein ES6-Versprechen zurückgibt?

Ähnlich wie diese Frage , aber anstatt zu fragen, wie Versprechen im Allgemeinen funktionieren, möchte ich speziell Folgendes wissen:

Was ist der Standard/beste Weg, um setTimeout in etwas zu verpacken, das Promise zurückgibt? Ich denke an etwas wie Angulars $timeout function , aber nicht Angular specific.

35
Michael Kropat

In Browsern

Vor allem nein - es gibt keine eingebauten dafür. Viele Bibliotheken, die ES2015 verbessern, versprechen wie Bluebird Peitsche mit ihm.

Ich denke, dass die andere Antwort die Ausführung der Funktion und eine Verzögerung zusammenbringt, es schafft auch Zeitüberschreitungen, die unmöglich abzubrechen sind. Ich würde es einfach schreiben als:

function delay(ms){
    var ctr, rej, p = new Promise(function (resolve, reject) {
        ctr = setTimeout(resolve, ms);
        rej = reject;
    });
    p.cancel = function(){ clearTimeout(ctr); rej(Error("Cancelled"))};
    return p; 
}

Dann können Sie tun:

delay(1000).then(/* ... do whatever */);

Oder

 doSomething().then(function(){ return delay(1000); }).then(doSomethingElse);

Wenn wir nur die Basisfunktionalität in ES2015 wollen, ist es noch einfacher als:

let delay = ms => new Promise(r => setTimeout(r, ms));

Im Knoten

Sie können util.promisify auf setTimeout, um eine delay -Funktion zurückzugewinnen - das heißt, Sie müssen nicht new Promise Konstruktor mehr.

48

So würde ich es implementieren:

function delay(duration, func) {
  var args = Array.prototype.slice.call(arguments, 2);

  return new Promise(function (resolve) {
    setTimeout(function () {
      resolve(func.apply(null, args));
    }, duration);
  });
}

(ES5-Syntax absichtlich gewählt)

Aber vielleicht gibt es eine gemeinsame Bibliothek, die dies bereits tut, oder eine bessere Möglichkeit, dies zu tun.

4
Michael Kropat

Wenn Sie die richtige Stornierung des versprochenen Timeouts ähnlich wie bei clearTimeout benötigen, ist es nicht bequem, das Versprechen direkt von setTimeout zurückzugeben . Besonders bei Verwendung mit ES7 async/await im Block try...finally. Es ist besser, eine separate Variable für die Timeout-Manipulation zu haben. Ich habe diesen Ansatz als winziges Wartezeitüberschreitung Paket implementiert. Es funktioniert wie folgt:

import Timeout from 'await-timeout';

async function foo() {
  const timeout = new Timeout();
  try {
    const fetchPromise = fetch('https://example.com');
    const timerPromise = timeout.set(1000).then(() => console.log('Timeout!'));
    await Promise.race([fetchPromise, timerPromise]);
  } finally {
    timeout.clear();
  }
}

In diesem Beispiel wird die Zeitüberschreitung definitiv gelöscht, wenn der Abruf erfolgreich war oder ein Fehler aufgetreten ist, und console.log('Timeout!') wird nicht aufgerufen.

1
vitalets