2017-05-28 4 views
1

ich diesen Code haben:Wie Versprechen tun guarentee, dass die ‚Entschlossenheit‘ Funktion nach einer asynchronen Operation ausgeführt wird

var myFirstPromise2 = new Promise((resolve, reject) => { 
    //setTimeout models an operation that takes a long time 
    setTimeout(function(){console.log('finishTimeout')},60000); 
    resolve('success'); 
}); 

myFirstPromise2.then((successMessage) => { 
    console.log('yay '+successMessage); 
}); 

Die Ausgabe lautet:

yay success 
finishTimeout 

Ich möchte resolve() nach der ausgeführt werden soll, langwierige Operation ist beendet, so dass die Ausgänge vertauscht sind.

Ich bin auch verwirrt über Versprechungen im Allgemeinen. Der obige Code ist nicht anders als einfach dies zu tun:

setTimeout(function(){console.log('finishTimeout')},60000); 
console.log('yay success'); 

EDIT: Was ist der Unterschied zwischen dem, resolve() innerhalb setTimeout setzen, und nur dies:

setTimeout(function() { 
    console.log('finishTimeout') 
    console.log("yay success") 
},60000) 
+5

Sie müssen 'resolve()' innerhalb des Callbacks des Timeout nach der 'endTimeout' Log-Anweisung aufrufen. Ihr aktueller Code ruft 'resolve()' auf, bevor die Zeitüberschreitung abgeschlossen ist. Übrigens sollte 'myFirstPromise3' nicht' myFirstPromise2' sein. – nnnnnn

+0

Sie sollten in der Lage sein, die Auflösung innerhalb des setTimeout nach der Anweisung 'console.log ('finishTimeout)' zu setzen. 'console.log ('finishTimeout'); resole ('Erfolg'); ' –

+0

Hier ist ein Codepen Beispiel: https://codepen.io/arecvlohe/pen/XRwjOX?editors=0012 –

Antwort

5

Wie Versprechen garantieren, dass die ‚Entschlossenheit‘ Funktion nach einer asynchronen Operation ausgeführt wird

Sie dies nicht tun. Versprechen sind nur ein Benachrichtigungs- und Fehlerfortpflanzungssystem. Sie lösen nur ein Versprechen, wenn ein Code resolve() aufruft, um das Versprechen zu lösen. Sie sollten resolve() nicht aufrufen, bis die asynchrone Operation tatsächlich ausgeführt wird. Wenn Sie resolve() zu früh aufrufen (wie Sie es getan haben), wird das Versprechen zu früh aufgelöst, bevor der asynchrone Vorgang abgeschlossen ist.

Ihr Code hier resolve() vor dem setTimeout() Rückruf tatsächlich Feuer und damit das Versprechen zu früh gelöst ruft: sollte

var myFirstPromise2 = new Promise((resolve, reject) => { 

    //setTimeout models an operation that takes a long time 
    setTimeout(function(){console.log('finishTimeout')},60000); 
    resolve('success'); 
}); 

Dieser Code dies sein, wo Entschlossenheit innerhalb der setTimeout() Rückruf aufgerufen wird, so das Versprechen nicht ist aufgelöst, bis der Timer ausgelöst hat,:

var myFirstPromise2 = new Promise((resolve, reject) => { 

    //setTimeout models an operation that takes a long time 
    setTimeout(function(){ 
     console.log('finishTimeout'); 
     resolve('success'); 
    },60000); 
}); 

Hinweis: resolve() nur aufgerufen, wenn der Asynchron-Betrieb tatsächlich getan. Ihre Version hat sie aufgerufen, bevor die asynchrone Operation ausgeführt wurde. Daher wurde die Zusage in Ihrer Version zu früh aufgelöst, bevor die asynchrone Operation ausgeführt wurde.

Versprechen haben KEINE magischen Kräfte zu wissen, wenn asynchrone Operationen ausgeführt werden. Sie machen nur genau das, was dein Code ihnen sagt. Rufen Sie also nur resolve() auf, wenn der asynchrone Vorgang tatsächlich ausgeführt wird.


EDIT: was ist der Unterschied Entschlossenheit innerhalb SetTimeout von nur diese zwischen setzen:

setTimeout(function() { 
    console.log('finishTimeout') 
    console.log("yay success") 
},60000); 

In diesem speziellen Beispiel wird dies gut funktionieren. Versprechen werden als Organisierungs- und Management-Tool für asynchrone Operationen verwendet. Sie sind äußerst nützlich, wenn Sie mehrere asynchrone Operationen ausführen müssen, die Sie sequenzieren oder koordinieren müssen, und sie sind äußerst nützlich, wenn Sie eine robuste Fehlerbehandlung mit mehreren asynchronen Operationen schreiben. Sie brauchen kein Versprechen für eine einfache, einmalige Timer-Operation.

Aber sobald Sie anfangen, Versprechungen für die hohen Nutzungen zu verwenden, werden Sie feststellen, dass sie nur eine bessere Möglichkeit sind, alle Ihre asynchronen Operationen, auch die einfacheren, zu entwerfen und zu programmieren. Sie werden feststellen, dass Sie sie für fast jede asynchrone Operation verwenden möchten. Sie müssen das nicht, aber nach meiner Erfahrung ist es einfacher und einfacher, sie für alle asynchronen Vorgänge zu verwenden.

Hinweis: Technisch gibt es einen kleinen Unterschied zwischen diesen:

setTimeout(function() { 
    console.log('finishTimeout') 
    console.log("yay success") 
},60000); 

Und dies:

var myFirstPromise2 = new Promise((resolve, reject) => { 

    //setTimeout models an operation that takes a long time 
    setTimeout(function(){ 
     console.log('finishTimeout'); 
     resolve('success'); 
    },60000); 
}); 

myFirstPromise2.then((successMessage) => { 
    console.log('yay '+successMessage); 
}); 

Da alle .then() Handler auf der nächsten Tick ausgeführt werden, wird es ein wenig sein Verzögerung zwischen den beiden console.log()-Operationen im zweiten Codebeispiel (gemessen in ms) gegenüber der ersten. Es ist wahrscheinlich nicht materiell, aber da Sie gefragt haben, was der Unterschied ist, dachte ich, ich würde diesen kleinen Unterschied aufzeigen. Es gibt praktische Gründe, warum es so entworfen wird, die insgesamt eine gute Designentscheidung sind (Stacks werden abgewickelt, bevor .then() Handler aufgerufen werden, Resolve sind durchweg asynchron, auch wenn das Versprechen synchron gelöst wird, etc ...).

0

Der Grund, warum es nicht funktioniert wie erwartet ist, weil resolve synchron anstelle von asynchron zurückgegeben wird. Das ist das Großartige an Versprechen ist, dass Sie die Lösung innerhalb eines asynchronen Prozesses bestehen können und wenn der Prozess fertig ist, wird die Ausführung von resolve als Callback aufgerufen. Deshalb können Sie:

setTimeout(function() { 
    console.log('finishTimeout') 
    resolve("success") 
},60000) 

Und es sollte wie erwartet funktionieren.

+2

'Auflösung' wird nicht synchron zurückgegeben. Es wird immer noch asynchron nur in Form einer [mikrotask] (https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/) in der Ereignisschleife zurückgegeben, die vor normal geplanten Aufgaben wie denen ausgeführt wird geplant von 'setTimeout' – nem035

1

Es gibt absolut nichts Magisches. Wie bereits gesagt, müssen Sie manuell resolve (oder reject) mit dem Wert, den Sie weitergeben möchten, aufrufen, und Sie müssen sicherstellen, dass Sie dies tun, wenn Ihr Code aufgelöst wurde. Das bedeutet, dass Sie, wenn es sich um eine asynchrone Aufgabe handelt, den Rückruf dieser Aufgabe lösen. nicht bevor.

All dies macht Funktionen zur Verfügung, die zuvor definiert wurden, und schießt Werte stromabwärts.

function Promise (task) { 
    let onSuccess; 
    let onError; 
    let resolve = value => onSuccess(value); 
    let reject = err => onError(err); 

    task(resolve, reject); 

    return { 
    then: (handleSuccess, handleError) => { 
     return Promise(function (resolve, reject) { 
     onSuccess = result => { 
      const value = handleSuccess(result); 
      if (value && value.then) { 
      value.then(resolve, reject); 
      } else { 
      resolve(value); 
      } 
     }; 
     onError = error => { 
      const value = handleError(error); 
      if (value && value.then) { 
      value.then(resolve, reject); 
      } else { 
      resolve(value); 
      } 
     }; 
     }); 
    } 
    }; 
} 

Beachten Sie, dass dies eine unzureichende Implementierung einer Promise ist; Diese Version würde nur für asynchronen Code funktionieren und es fehlen viele Anwendungsfälle. Aber die wichtigen Mechanismen sind da, um sie zu analysieren.

Wenn Sie dann anrufen und ihm Handler geben, wird ein neues Versprechen zurückgegeben. Die Aufgabe dieses Versprechens besteht im Wesentlichen darin, den Erfolg oder Misserfolg der Muttergesellschaft Promise zu unterstützen, und so weiter.

Wie Sie sehen können, gibt es in einem Promise keinen magischen Pausenknopf, mit dem Sie wissen können, wann eine Aufgabe beendet ist. Es ist wirklich nur interne Rückrufe einrichten, die das nächste Versprechen auslösen auch zu vervollständigen.

Sie können eine vollständige Implementierung von ES6 Promises in ~ 100 Codezeilen vornehmen, sobald Sie alle Fehlerbehandlung und Callback-Warteschlangen und Statusverwaltung berücksichtigt haben.

Future ist eine Struktur wie eine Promise aber ist einfacher zu implementieren (obwohl schwieriger, den Kopf herumzuwickeln, wenn Sie nicht an die funktionale Programmierung gewöhnt sind).

function Future (task) { 
    return { 
    map: 
     f => 
     Future((reject, resolve) => 
      task(reject, x => resolve(f(x)))), 

    chain: 
     f => 
     Future((reject, resolve) => 
      task(reject, x => f(x).fork(reject, resolve))), 

    fork: task 
    }; 
} 

Future.of = x => Future((_, resolve) => resolve(x)); 
Future.resolved = Future.of; 
Future.rejected = err => Future(reject => reject(err)); 

Wirklich, können Sie bei der Umsetzung von map in diesem Beispiel sehen, und die gleiche Art von Planung von eventuellem Rückruf als onSuccess vorher sehen. Um ehrlich zu sein, gibt es nicht viel mehr in der Art, Future zu implementieren als das, was Sie sehen. Der Grund, warum es einfacher ist, ist einfach, weil es den Async-Code nicht ausführt, bis Sie fork manuell aufrufen und Fehler- und Erfolgshandler übergeben, und weil es nicht versucht, herauszufinden, ob Sie ein Versprechen aus einer Zusage zurückgeben oder abonnieren Führen Sie einfach einen Rückruf ...

... Wenn Sie nur einen Wert zurückgeben möchten, verwenden Sie Karte, wenn Sie eine Zukunft eines Werts zurückgeben möchten, verwenden Sie dann Kette.

const app = Future.of(20) 
    .map(x => x * 2) 
    .chain(x => Future.of(x/4)); 

app.fork(err => console.log(err), num => console.log(num)); // 10 
+0

Eine Frage über' Aufgabe (auflösen, ablehnen); 'auf der 6. Zeile von Premise. Was passiert, wenn die Auflösung in der Task aufgerufen wird, bevor eine Funktion für onSuccess registriert wird? – varimax

+0

@varimax wie die Antwort sagt, in diesem speziellen, nicht-konforme Umsetzung von 'Promise', das wäre ein Problem. In echtem "Versprechen" wäre das der einfache Fall. Es würde eine Variable geben, die den Zustand und den aufgelösten Wert enthält, und einige Funktionen, um den Zustand zu ändern und sicherzustellen, dass der Zustand nur einmal geändert werden kann, und all das gute Zeug. ... aber wenn Ihr Versprechen sofort verrechnet wird, bedeutet das nur, dass Sie den einfachen Pfad für alle 'then' Aufrufe durchlaufen müssen, weil Sie bereits wissen, ob es erfolgreich war oder fehlgeschlagen ist. – Norguard

+0

Ich habe das Zeug nicht aufgenommen, weil es nicht wichtig war. Wie ich schon sagte, können Sie die Spezifikation für das Versprechen in ~ 100 Zeilen Code implementieren. Abgesehen davon benötigen Sie auch eine Warteschlange und ein Warteschlangen-Management-System für Thens, die ausgelöst werden, bevor das Versprechen gelöst wird, weil Sie mehrere Personen das 'then' des gleichen Versprechens zum Abonnieren verwenden können, so müssen Sie sammle sie alle. Dann haben Sie einen Code-Pfad, um festzustellen, ob Sie Schlange stehen oder direkt feuern ... und so weiter ... Das ist, wie vielversprechende Spezifikationen sich auf 100+ LoC ausdehnen. Die zukünftige Implementierung ist praktisch abgeschlossen. – Norguard

Verwandte Themen