webentwicklung-frage-antwort-db.com.de

Wie wird eine Promise / Defer-Bibliothek implementiert?

Wie ist eine Promise/Defer-Bibliothek wie q implementiert? Ich habe versucht, den Quellcode zu lesen, fand es aber ziemlich schwer zu verstehen, und ich fand es großartig, wenn mir jemand von einer hohen Ebene erklären könnte, welche Techniken zum Implementieren von Versprechungen in Single-Thread-JS-Umgebungen verwendet werden wie Node und Browser.

74
Derek Chiang

Ich finde es schwieriger zu erklären, als ein Beispiel zu zeigen, daher hier eine sehr einfache Implementierung dessen, was ein Aufschub/ein Versprechen sein könnte.

Haftungsausschluss: Dies ist keine funktionale Implementierung und einige Teile der Promise/A-Spezifikation fehlen. Dies ist nur zur Erläuterung der Grundlage der Versprechen.

tl; dr: Gehen Sie zum Abschnitt Klassen erstellen und Beispiel , um dies anzuzeigen vollständige Umsetzung.

Versprechen:

Zuerst müssen wir ein Versprechen-Objekt mit einer Reihe von Rückrufen erstellen. Ich beginne mit der Arbeit mit Objekten, weil es klarer ist:

var promise = {
  callbacks: []
}

jetzt fügen Sie Rückrufe mit der Methode hinzu, dann:

var promise = {
  callbacks: [],
  then: function (callback) {
    callbacks.Push(callback);
  }
}

Und wir brauchen auch die Fehler-Rückrufe:

var promise = {
  okCallbacks: [],
  koCallbacks: [],
  then: function (okCallback, koCallback) {
    okCallbacks.Push(okCallback);
    if (koCallback) {
      koCallbacks.Push(koCallback);
    }
  }
}

Verschieben:

Erstellen Sie nun das verzögerte Objekt, das ein Versprechen enthält:

var defer = {
  promise: promise
};

Der Aufschub muss aufgelöst werden:

var defer = {
  promise: promise,
  resolve: function (data) {
    this.promise.okCallbacks.forEach(function(callback) {
      window.setTimeout(function () {
        callback(data)
      }, 0);
    });
  },
};

Und muss ablehnen:

var defer = {
  promise: promise,
  resolve: function (data) {
    this.promise.okCallbacks.forEach(function(callback) {
      window.setTimeout(function () {
        callback(data)
      }, 0);
    });
  },

  reject: function (error) {
    this.promise.koCallbacks.forEach(function(callback) {
      window.setTimeout(function () {
        callback(error)
      }, 0);
    });
  }
};

Beachten Sie, dass die Rückrufe in einem Timeout aufgerufen werden, damit der Code immer asynchron ist.

Und das ist es, was eine grundlegende Implementierung von Aufschub/Versprechen benötigt.

Erstellen Sie Klassen und Beispiel:

Lassen Sie uns nun beide Objekte in Klassen konvertieren, zunächst das Versprechen:

var Promise = function () {
  this.okCallbacks = [];
  this.koCallbacks = [];
};

Promise.prototype = {
  okCallbacks: null,
  koCallbacks: null,
  then: function (okCallback, koCallback) {
    okCallbacks.Push(okCallback);
    if (koCallback) {
      koCallbacks.Push(koCallback);
    }
  }
};

Und jetzt der Aufschub:

var Defer = function () {
  this.promise = new Promise();
};

Defer.prototype = {
  promise: null,
  resolve: function (data) {
    this.promise.okCallbacks.forEach(function(callback) {
      window.setTimeout(function () {
        callback(data)
      }, 0);
    });
  },

  reject: function (error) {
    this.promise.koCallbacks.forEach(function(callback) {
      window.setTimeout(function () {
        callback(error)
      }, 0);
    });
  }
};

Und hier ist ein Anwendungsbeispiel:

function test() {
  var defer = new Defer();
  // an example of an async call
  serverCall(function (request) {
    if (request.status === 200) {
      defer.resolve(request.responseText);
    } else {
      defer.reject(new Error("Status code was " + request.status));
    }
  });
  return defer.promise;
}

test().then(function (text) {
  alert(text);
}, function (error) {
  alert(error.message);
});

Wie Sie sehen können, sind die grundlegenden Teile einfach und klein. Es wächst, wenn Sie andere Optionen hinzufügen, z. B. die Auflösung mehrerer Versprechen:

Defer.all(promiseA, promiseB, promiseC).then()

oder versprich Verkettung:

getUserById(id).then(getFilesByUser).then(deleteFile).then(promptResult);

Um mehr über die Spezifikationen zu erfahren: CommonJS Promise Specification . Beachten Sie, dass die Hauptbibliotheken (Q, when.js, rsvp.js, node-promise, ...) der Angabe Promises/A folgen.

Hoffe ich war klar genug.

Bearbeiten:

Wie in den Kommentaren gefragt, habe ich in dieser Version zwei Dinge hinzugefügt:

  • Die Möglichkeit, dann von einem Versprechen abzurufen, egal welchen Status es hat.
  • Die Möglichkeit, Versprechen zu verketten.

Um das Versprechen bei seiner Auflösung anrufen zu können, müssen Sie den Status zum Versprechen hinzufügen. Wenn das dann aufgerufen wird, überprüfen Sie diesen Status. Wenn der Status aufgelöst oder abgelehnt wird, führen Sie einfach den Rückruf mit seinen Daten oder Fehlern aus.

Um Versprechen verketten zu können, müssen Sie für jeden Aufruf von then einen neuen Aufschub generieren und, wenn das Versprechen gelöst/abgelehnt wurde, das neue Versprechen mit dem Ergebnis des Rückrufs lösen/ablehnen. Wenn also das Versprechen erfüllt ist und der Rückruf ein neues Versprechen zurückgibt, ist er an das mit der Funktion then() zurückgegebene Versprechen gebunden. Wenn nicht, wird das Versprechen mit dem Ergebnis des Rückrufs aufgelöst.

Hier ist das Versprechen:

var Promise = function () {
  this.okCallbacks = [];
  this.koCallbacks = [];
};

Promise.prototype = {
  okCallbacks: null,
  koCallbacks: null,
  status: 'pending',
  error: null,

  then: function (okCallback, koCallback) {
    var defer = new Defer();

    // Add callbacks to the arrays with the defer binded to these callbacks
    this.okCallbacks.Push({
      func: okCallback,
      defer: defer
    });

    if (koCallback) {
      this.koCallbacks.Push({
        func: koCallback,
        defer: defer
      });
    }

    // Check if the promise is not pending. If not call the callback
    if (this.status === 'resolved') {
      this.executeCallback({
        func: okCallback,
        defer: defer
      }, this.data)
    } else if(this.status === 'rejected') {
      this.executeCallback({
        func: koCallback,
        defer: defer
      }, this.error)
    }

    return defer.promise;
  },

  executeCallback: function (callbackData, result) {
    window.setTimeout(function () {
      var res = callbackData.func(result);
      if (res instanceof Promise) {
        callbackData.defer.bind(res);
      } else {
        callbackData.defer.resolve(res);
      }
    }, 0);
  }
};

Und der Aufschub:

var Defer = function () {
  this.promise = new Promise();
};

Defer.prototype = {
  promise: null,
  resolve: function (data) {
    var promise = this.promise;
    promise.data = data;
    promise.status = 'resolved';
    promise.okCallbacks.forEach(function(callbackData) {
      promise.executeCallback(callbackData, data);
    });
  },

  reject: function (error) {
    var promise = this.promise;
    promise.error = error;
    promise.status = 'rejected';
    promise.koCallbacks.forEach(function(callbackData) {
      promise.executeCallback(callbackData, error);
    });
  },

  // Make this promise behave like another promise:
  // When the other promise is resolved/rejected this is also resolved/rejected
  // with the same data
  bind: function (promise) {
    var that = this;
    promise.then(function (res) {
      that.resolve(res);
    }, function (err) {
      that.reject(err);
    })
  }
};

Wie Sie sehen, ist es ziemlich gewachsen.

148
Kaizo

Q ist eine sehr komplexe Versprechungsbibliothek in Bezug auf die Implementierung, da sie Pipelining- und RPC-Szenarien unterstützen soll. Ich habe meine eigene Implementierung der Promises/A + Spezifikation hier .

Im Prinzip ist es ganz einfach. Bevor das Versprechen geklärt/geklärt wird, protokollieren Sie alle Rückrufe oder Fehler, indem Sie sie in ein Array verschieben. Wenn das Versprechen erfüllt ist, rufen Sie die entsprechenden Rückrufe oder Fehler auf und notieren, mit welchem ​​Ergebnis das Versprechen abgerechnet wurde (und ob es erfüllt oder abgelehnt wurde). Nachdem es erledigt ist, rufen Sie einfach die Rückrufe oder Fehler mit dem gespeicherten Ergebnis auf.

Das gibt Ihnen ungefähr die Semantik von done. Um then zu erstellen, müssen Sie nur ein neues Versprechen zurückgeben, das mit dem Ergebnis des Aufrufs der Rückrufe/Errbacks aufgelöst wird.

Wenn Sie daran interessiert sind, die Gründe für die Entwicklung einer vollständigen Implementierung mit Unterstützung für RPC und Pipelining wie Q umfassend zu erläutern, können Sie die Gründe von kriskowal lesen hier . Es ist ein wirklich netter, abgestufter Ansatz, den ich nicht genug empfehlen kann, wenn Sie Versprechen umsetzen möchten. Es ist wahrscheinlich eine Lektüre wert, auch wenn Sie nur eine Versprechenbibliothek verwenden werden.

7
ForbesLindesay

Wie Forbes in seiner Antwort erwähnt, habe ich viele der Entwurfsentscheidungen festgehalten, die bei der Erstellung einer Bibliothek wie Q getroffen wurden, hier https://github.com/kriskowal/q/tree/v1/design . Es genügt zu sagen, es gibt Ebenen einer Versprechen-Bibliothek und viele Bibliotheken, die auf verschiedenen Ebenen anhalten.

Auf der ersten Ebene, die von der Promises/A + -Spezifikation erfasst wird, ist ein Versprechen ein Proxy für ein eventuelles Ergebnis und eignet sich zum Verwalten der „lokalen Asynchronität“ . Das heißt, es ist geeignet, um sicherzustellen, dass die Arbeit in der richtigen Reihenfolge ausgeführt wird, und um sicherzustellen, dass es einfach und unkompliziert ist, auf das Ergebnis einer Operation zu achten, unabhängig davon, ob sie bereits ausgeführt wurde oder in Zukunft ausgeführt wird. Dies macht es auch für eine oder mehrere Parteien genauso einfach, ein eventuelles Ergebnis zu abonnieren.

Q bietet, wie ich es implementiert habe, Versprechungen, die als Ersatz für eventuelle, entfernte oder eventuelle + entfernte Ergebnisse dienen. Zu diesem Zweck wird das Design invertiert, mit verschiedenen Implementierungen für Versprechungen - zurückgestellte Versprechungen, erfüllte Versprechungen, abgelehnte Versprechungen und Versprechungen für entfernte Objekte (die letzte wird in Q-Connection implementiert). Sie teilen sich alle die gleiche Schnittstelle und senden und empfangen Nachrichten wie "then" (was für Promises/A + ausreichend ist), aber auch "get" und "invoke". Also handelt es sich bei Q um "verteilte Asynchronität" , die auf einer anderen Ebene existiert.

Q wurde jedoch tatsächlich von einer höheren Ebene entfernt, in der Versprechen für die Verwaltung der verteilten Asynchronität zwischen gegenseitig verdächtigen Parteien wie Ihnen, einem Händler, einer Bank, verwendet werden , Facebook, die Regierung - keine Feinde, vielleicht sogar Freunde, aber manchmal mit Interessenkonflikten. Das Q, das ich implementiert habe, ist so konzipiert, dass es mit gehärteten Sicherheitsversprechen kompatibel ist (was der Grund für die Trennung von promise und resolve ist), mit der Hoffnung, dass es die Leute dazu bringt, Versprechungen zu machen und sie zu schulen Erlauben Sie ihnen, ihren Code mitzunehmen, wenn sie in Zukunft Versprechungen in sicheren Mashups verwenden müssen.

Natürlich gibt es Kompromisse, wenn Sie die Ebenen nach oben bewegen, in der Regel in der Geschwindigkeit. Versprechungen können also auch so konzipiert werden, dass sie nebeneinander existieren. Hier setzt das Konzept eines "thenable" an. Versprechensbibliotheken auf jeder Ebene können so entworfen werden, dass sie Versprechungen von jeder anderen Ebene verwenden, sodass mehrere Implementierungen nebeneinander existieren können und Benutzer nur das kaufen können, was sie benötigen.

Trotzdem gibt es keine Entschuldigung dafür, schwer zu lesen. Domenic und ich arbeiten an einer Version von Q, die modularer und zugänglicher sein wird, wobei einige der störenden Abhängigkeiten und Umgehungen in andere Module und Pakete verschoben werden. Zum Glück haben Leute wie Forbes , Crockford und andere die Bildungslücke geschlossen, indem sie einfachere Bibliotheken geschaffen haben.

6
Kris Kowal

Stellen Sie zunächst sicher, dass Sie verstehen, wie Versprechen funktionieren sollen. Schauen Sie sich dazu die CommonJs Promises suggestions und die Promises/A + specification an.

Es gibt zwei grundlegende Konzepte, die jeweils in wenigen einfachen Zeilen implementiert werden können:

  • Ein Versprechen wird mit dem Ergebnis asynchron aufgelöst. Das Hinzufügen von Rückrufen ist eine transparente Aktion - unabhängig davon, ob das Versprechen bereits eingelöst wurde oder nicht, werden sie mit dem Ergebnis abgerufen, sobald es verfügbar ist.

    function Deferred() {
        var callbacks = [], // list of callbacks
            result; // the resolve arguments or undefined until they're available
        this.resolve = function() {
            if (result) return; // if already settled, abort
            result = arguments; // settle the result
            for (var c;c=callbacks.shift();) // execute stored callbacks
                c.apply(null, result);
        });
        // create Promise interface with a function to add callbacks:
        this.promise = new Promise(function add(c) {
            if (result) // when results are available
                c.apply(null, result); // call it immediately
            else
                callbacks.Push(c); // put it on the list to be executed later
        });
    }
    // just an interface for inheritance
    function Promise(add) {
        this.addCallback = add;
    }
    
  • Versprechen haben eine then -Methode, mit der sie verkettet werden können. Ich nehme einen Rückruf entgegen und sende ein neues Versprechen zurück, das mit dem Ergebnis dieses Rückrufs aufgelöst wird, nachdem es mit dem Ergebnis des ersten Versprechens aufgerufen wurde. Wenn der Rückruf ein Versprechen zurückgibt, wird es assimiliert, anstatt verschachtelt zu werden.

    Promise.prototype.then = function(fn) {
        var dfd = new Deferred(); // create a new result Deferred
        this.addCallback(function() { // when `this` resolves…
            // execute the callback with the results
            var result = fn.apply(null, arguments);
            // check whether it returned a promise
            if (result instanceof Promise)
                result.addCallback(dfd.resolve); // then hook the resolution on it
            else
                dfd.resolve(result); // resolve the new promise immediately 
            });
        });
        // and return the new Promise
        return dfd.promise;
    };
    

Weitere Konzepte wären das Beibehalten eines separaten Fehlerzustands (mit einem zusätzlichen Rückruf dafür) und das Abfangen von Ausnahmen in den Handlern oder das Gewährleisten der Asynchronität für die Rückrufe. Sobald Sie diese hinzugefügt haben, haben Sie eine voll funktionsfähige Promise-Implementierung.

Hier ist die Fehlersache ausgeschrieben. Es ist leider ziemlich repetitiv; Sie können es besser machen, indem Sie zusätzliche Verschlüsse verwenden, aber dann wird es wirklich sehr, sehr schwer zu verstehen.

function Deferred() {
    var callbacks = [], // list of callbacks
        errbacks = [], // list of errbacks
        value, // the fulfill arguments or undefined until they're available
        reason; // the error arguments or undefined until they're available
    this.fulfill = function() {
        if (reason || value) return false; // can't change state
        value = arguments; // settle the result
        for (var c;c=callbacks.shift();)
            c.apply(null, value);
        errbacks.length = 0; // clear stored errbacks
    });
    this.reject = function() {
        if (value || reason) return false; // can't change state
        reason = arguments; // settle the errror
        for (var c;c=errbacks.shift();)
            c.apply(null, reason);
        callbacks.length = 0; // clear stored callbacks
    });
    this.promise = new Promise(function add(c) {
        if (reason) return; // nothing to do
        if (value)
            c.apply(null, value);
        else
            callbacks.Push(c);
    }, function add(c) {
        if (value) return; // nothing to do
        if (reason)
            c.apply(null, reason);
        else
            errbacks.Push(c);
    });
}
function Promise(addC, addE) {
    this.addCallback = addC;
    this.addErrback = addE;
}
Promise.prototype.then = function(fn, err) {
    var dfd = new Deferred();
    this.addCallback(function() { // when `this` is fulfilled…
        try {
            var result = fn.apply(null, arguments);
            if (result instanceof Promise) {
                result.addCallback(dfd.fulfill);
                result.addErrback(dfd.reject);
            } else
                dfd.fulfill(result);
        } catch(e) { // when an exception was thrown
            dfd.reject(e);
        }
    });
    this.addErrback(err ? function() { // when `this` is rejected…
        try {
            var result = err.apply(null, arguments);
            if (result instanceof Promise) {
                result.addCallback(dfd.fulfill);
                result.addErrback(dfd.reject);
            } else
                dfd.fulfill(result);
        } catch(e) { // when an exception was re-thrown
            dfd.reject(e);
        }
    } : dfd.reject); // when no `err` handler is passed then just propagate
    return dfd.promise;
};
4
Bergi

Vielleicht möchten Sie das Blog-Beitrag auf Adehun überprüfen.

Adehun ist eine extrem leichte Implementierung (ca. 166 LOC) und sehr nützlich, um zu lernen, wie die Promise/A + -Spezifikation implementiert wird.

Haftungsausschluss : Ich habe den Blog-Beitrag geschrieben, aber der Blog-Beitrag erklärt alles über Adehun.

Die Übergangsfunktion - Gatekeeper für den Zustandsübergang

Gatekeeper-Funktion; stellt sicher, dass Zustandsübergänge stattfinden, wenn alle erforderlichen Bedingungen erfüllt sind.

Wenn die Bedingungen erfüllt sind, aktualisiert diese Funktion den Status und den Wert des Versprechens. Es löst dann die Prozessfunktion zur weiteren Bearbeitung aus.

Die Prozessfunktion führt die richtige Aktion basierend auf dem Übergang aus (z. B. ausstehend bis erfüllt) und wird später erläutert.

function transition (state, value) {
  if (this.state === state ||
    this.state !== validStates.PENDING ||
    !isValidState(state)) {
      return;
    }

  this.value = value;
  this.state = state;
  this.process();
}

Die Then-Funktion

Die then-Funktion akzeptiert zwei optionale Argumente (onFulfill- und onReject-Handler) und muss ein neues Versprechen zurückgeben. Zwei Hauptanforderungen:

  1. Das Basisversprechen (dasjenige, auf dem dann aufgerufen wird) muss unter Verwendung der übergebenen Handler ein neues Versprechen erstellen. Die Basis speichert auch einen internen Verweis auf dieses erstellte Versprechen, sodass es aufgerufen werden kann, sobald das Basisversprechen erfüllt/abgelehnt wurde.

  2. Wenn das Basisversprechen erfüllt oder abgelehnt wird, sollte der entsprechende Bearbeiter sofort angerufen werden. Adehun.js behandelt dieses Szenario, indem es in der then-Funktion process aufruft.

``

function then(onFulfilled, onRejected) {
    var queuedPromise = new Adehun();
    if (Utils.isFunction(onFulfilled)) {
        queuedPromise.handlers.fulfill = onFulfilled;
    }

    if (Utils.isFunction(onRejected)) {
        queuedPromise.handlers.reject = onRejected;
    }

    this.queue.Push(queuedPromise);
    this.process();

    return queuedPromise;
}`

Die Prozessfunktion - Übergänge verarbeiten

Dies wird nach Zustandsübergängen oder beim Aufruf der then-Funktion aufgerufen. Daher muss nach ausstehenden Versprechungen gesucht werden, da diese möglicherweise von der then-Funktion aufgerufen wurden.

Der Prozess führt das Promise Resolution-Verfahren für alle intern gespeicherten Versprechen aus (d. H. Für diejenigen, die über die then-Funktion an das Basisversprechen angehängt wurden) und erzwingt die folgenden Promise/A + -Anforderungen:

  1. Asynchrones Aufrufen der Handler mithilfe des Hilfsprogramms Utils.runAsync (ein dünner Wrapper um setTimeout (setImmediate funktioniert auch)).

  2. Erstellen von Fallback-Handlern für die Handler onSuccess und onReject, falls diese fehlen.

  3. Auswählen der richtigen Handlerfunktion basierend auf dem Versprechungsstatus, z. erfüllt oder abgelehnt.

  4. Anwenden des Handlers auf den Wert des Basisversprechens. Der Wert dieser Operation wird an die Auflösungsfunktion übergeben, um den Versprechungsverarbeitungszyklus abzuschließen.

  5. Wenn ein Fehler auftritt, wird das angehängte Versprechen sofort abgelehnt.

    function process () {var that = this, erfülleFallBack = function (value) {Rückgabewert; }, rejectFallBack = function (reason) {throw reason; };

    if (this.state === validStates.PENDING) {
        return;
    }
    
    Utils.runAsync(function() {
        while (that.queue.length) {
            var queuedP = that.queue.shift(),
                handler = null,
                value;
    
            if (that.state === validStates.FULFILLED) {
                handler = queuedP.handlers.fulfill ||
                    fulfillFallBack;
            }
            if (that.state === validStates.REJECTED) {
                handler = queuedP.handlers.reject ||
                    rejectFallBack;
            }
    
            try {
                value = handler(that.value);
            } catch (e) {
                queuedP.reject(e);
                continue;
            }
    
            Resolve(queuedP, value);
        }
    });
    

    }

Die Auflösungsfunktion - Versprechen auflösen

Dies ist wahrscheinlich der wichtigste Teil der Implementierung von Versprechungen, da hier die Lösung von Versprechungen behandelt wird. Es akzeptiert zwei Parameter - das Versprechen und seinen Auflösungswert.

Zwar gibt es viele Überprüfungen für verschiedene mögliche Auflösungswerte; Die interessanten Lösungsszenarien sind zwei - diejenigen, bei denen ein Versprechen übergeben wird und ein dannbares (ein Objekt mit einem dann-Wert).

  1. Ein Versprechen abgeben

Wenn der Auflösungswert ein anderes Versprechen ist, muss das Versprechen den Status dieses Auflösungswerts annehmen. Da dieser Auflösungswert ausstehend oder abgerechnet werden kann, ist es am einfachsten, einen neuen Then-Handler an den Auflösungswert anzuhängen und das darin enthaltene ursprüngliche Versprechen zu handhaben. Wann immer es kommt, wird das ursprüngliche Versprechen gelöst oder abgelehnt.

  1. Übergabe eines gültigen Wertes

Der Haken dabei ist, dass die then-Funktion des then-Werts nur einmal aufgerufen werden muss (eine gute Verwendung für den once-Wrapper aus der funktionalen Programmierung). Ebenso ist das Versprechen sofort abzulehnen, wenn der Abruf der then-Funktion eine Exception auslöst.

Wie zuvor wird die then-Funktion mit Funktionen aufgerufen, die das Versprechen letztendlich auflösen oder ablehnen. Der Unterschied besteht jedoch darin, dass das aufgerufene Flag beim ersten Aufruf gesetzt wird und nachfolgende Aufrufe keine ops sind.

function Resolve(promise, x) {
  if (promise === x) {
    var msg = "Promise can't be value";
    promise.reject(new TypeError(msg));
  }
  else if (Utils.isPromise(x)) {
    if (x.state === validStates.PENDING){
      x.then(function (val) {
        Resolve(promise, val);
      }, function (reason) {
        promise.reject(reason);
      });
    } else {
      promise.transition(x.state, x.value);
    }
  }
  else if (Utils.isObject(x) ||
           Utils.isFunction(x)) {
    var called = false,
        thenHandler;

    try {
      thenHandler = x.then;

      if (Utils.isFunction(thenHandler)){
        thenHandler.call(x,
          function (y) {
            if (!called) {
              Resolve(promise, y);
              called = true;
            }
          }, function (r) {
            if (!called) {
              promise.reject(r);
              called = true;
            }
       });
     } else {
       promise.fulfill(x);
       called = true;
     }
   } catch (e) {
     if (!called) {
       promise.reject(e);
       called = true;
     }
   }
 }
 else {
   promise.fulfill(x);
 }
}

Der Versprechen-Konstruktor

Und das ist derjenige, der alles zusammenbringt. Die Funktionen "Erfüllen" und "Zurückweisen" sind syntaktische Zucker, die No-Op-Funktionen zum Auflösen und Zurückweisen übergeben.

var Adehun = function (fn) {
 var that = this;

 this.value = null;
 this.state = validStates.PENDING;
 this.queue = [];
 this.handlers = {
   fulfill : null,
   reject : null
 };

 if (fn) {
   fn(function (value) {
     Resolve(that, value);
   }, function (reason) {
     that.reject(reason);
   });
 }
};

Ich hoffe, dass dies dazu beigetragen hat, mehr Licht in die Art und Weise zu bringen, wie Versprechen funktionieren.

1