Heim > Web-Frontend > js-Tutorial > Hauptteil

Detaillierte Erläuterung der Rolle des Versprechenobjekts von jQuery in der asynchronen JavaScript-Programmierung_jquery

WBOY
Freigeben: 2016-05-16 15:02:24
Original
1279 Leute haben es durchsucht

Versprechen kann im Chinesischen als Wunsch verstanden werden, der das Endergebnis einer einzelnen Operation darstellt. Ein Versprechen hat drei Zustände: unerfüllt (unerfüllt), erfüllt (erfüllt) und fehlgeschlagen (fehlgeschlagen). Es können sowohl erfüllte als auch fehlgeschlagene Zustände überwacht werden. Ein Wunsch kann vom Zustand „unerfüllt“ in den Zustand „erfüllt“ oder „fehlgeschlagen“ wechseln. Sobald sich ein Wunsch im Zustand „erfüllt“ oder „fehlgeschlagen“ befindet, kann sein Status nicht geändert werden. Diese „unveränderliche“ Funktion ist für ein Versprechen sehr wichtig. Sie kann verhindern, dass der Status-Listener des Versprechens den Status eines Versprechens ändert und dazu führt, dass sich andere Listener abnormal verhalten. Beispiel: Wenn ein Listener, der den Status „erfüllt“ überwacht, den Status des Versprechens in „fehlgeschlagen“ ändert, wird der Listener im Status „fehlgeschlagen“ ausgelöst. Wenn ein Listener im Status „fehlgeschlagen“ den Status des Versprechens auf „erfüllt“ setzt, dann wird der Listener ausgelöst im erfüllten Zustand wird das Gerät ausgelöst, was zu einer Endlosschleife führt. Eine andere Möglichkeit, die Eigenschaften von Promise zu verstehen, besteht darin, sich Promise als eine Variable vom primitiven Typ in JavaScript vorzustellen. Diese Variable kann an die aufgerufene Funktion übergeben, aber von der aufrufenden Funktion nicht geändert werden.

Jedes Promise-Objekt verfügt über eine Methode: then(fulfilledHandler, errorHandler, progressHandler), die zur Überwachung der verschiedenen Zustände eines Promise verwendet wird. „filledHandler“ wird zum Abhören erfüllter Ereignisse, „errorHandler“ zum Abhören fehlgeschlagener Ereignisse und „progressHandler“ zum Abhören von Fortschrittsereignissen verwendet. Ein Promise erzwingt nicht die Implementierung der Überwachung von Fortschrittsstatusereignissen (jQuerys Deferred ist eine Implementierung von Promise, implementiert jedoch nicht die Verarbeitung von Fortschrittsstatusereignissen).

Der Rückgabewert von „filledHandler“ und „errorHandler“ in der Funktion „then(...)“ ist ein neues Promise-Objekt, sodass die Funktion „then(...)“ in einer Kette aufgerufen werden kann. Unter normalen Umständen gibt jede Callback-Funktion ein Promise im erfüllten Zustand zurück. Wenn die Callback-Funktion einen Fehlerwert zurückgibt, wird der zurückgegebene Promise-Status fehlgeschlagen.

Die Rolle des Versprechens in der asynchronen Programmierung

Der asynchrone Modus wird in der Webprogrammierung immer wichtiger. Aus diesem Grund ist dieser Modus nicht sehr einfach zu implementieren Es handelt sich um eine Abstraktion des Versprechens (manchmal auch als aufgeschoben bezeichnet). Über diese Bibliotheken können Entwickler das Promise-Muster in der tatsächlichen Programmierung verwenden.
Mit der Vertiefung der Web 2.0-Technologie wird der Rechendruck auf der Browserseite immer größer, sodass „Parallelität“ eine positive Bedeutung hat. Für Entwickler müssen sie nicht nur die Interaktion zwischen der Seite und dem Benutzer unberührt lassen, sondern auch die Beziehung zwischen der Seite und asynchronen Aufgaben koordinieren. Diese Art von nichtlinearen Ausführungsprogrammieranforderungen stellt Schwierigkeiten bei der Anpassung dar. Abgesehen von der Seiteninteraktion können wir uns zwei Ergebnisse vorstellen, die für asynchrone Aufrufe verarbeitet werden müssen: erfolgreiche Vorgänge und Fehlerverarbeitung. Nach einem erfolgreichen Aufruf müssen wir das zurückgegebene Ergebnis möglicherweise in einer anderen Ajax-Anfrage verwenden, was zu einer „Funktionsketten“-Situation führt. Diese Situation führt zu Programmierkomplikationen. Schauen Sie sich das folgende Codebeispiel an (basierend auf XMLHttpRequest2):

function searchTwitter(term, onload, onerror) {
 
   var xhr, results, url;
   url = 'http://search.twitter.com/search.json?rpp=100&q=' + term;
   xhr = new XMLHttpRequest();
   xhr.open('GET', url, true);
 
   xhr.onload = function (e) {
     if (this.status === 200) {
       results = JSON.parse(this.responseText);
       onload(results);
     }
   };
 
   xhr.onerror = function (e) {
     onerror(e);
   };
 
   xhr.send();
 }
 
 function handleError(error) {
   /* handle the error */
 }
 
 function concatResults() {
   /* order tweets by date */
 }
 
 function loadTweets() {
   var container = document.getElementById('container');
 
   searchTwitter('#IE10', function (data1) {
     searchTwitter('#IE9', function (data2) {
       /* Reshuffle due to date */
       var totalResults = concatResults(data1.results, data2.results);
       totalResults.forEach(function (tweet) {
         var el = document.createElement('li');
         el.innerText = tweet.text;
         container.appendChild(el);
       });
     }, handleError);
   }, handleError);
 }
Nach dem Login kopieren

Die Funktion des obigen Codes besteht darin, den Inhalt mit den Hashtags IE10 und IE9 in Twitter abzurufen und auf der Seite anzuzeigen. Diese Art von verschachtelter Rückruffunktion ist schwer zu verstehen. Entwickler müssen sorgfältig analysieren, welcher Code für die Geschäftslogik der Anwendung verwendet wird und welcher Code asynchrone Funktionsaufrufe verarbeitet. Die Fehlerbehandlung ist ebenfalls zerlegt. Wir müssen das Auftreten von Fehlern an verschiedenen Stellen erkennen und entsprechend behandeln.

Um die Komplexität der asynchronen Programmierung zu reduzieren, haben Entwickler nach einfachen Möglichkeiten zur Handhabung asynchroner Vorgänge gesucht. Eines dieser Verarbeitungsmuster wird als Versprechen bezeichnet und stellt das Ergebnis eines Vorgangs dar, der möglicherweise lange dauert und nicht unbedingt abgeschlossen sein muss. Dieses Muster blockiert nicht und wartet nicht auf den Abschluss eines langen Vorgangs, sondern gibt ein Objekt zurück, das das versprochene Ergebnis darstellt.

Stellen Sie sich ein Beispiel vor, bei dem der Seitencode auf eine Drittanbieter-API zugreifen muss. Netzwerkverzögerungen können zu längeren Antwortzeiten führen. In diesem Fall hat die Verwendung asynchroner Programmierung keinen Einfluss auf die Interaktion zwischen der gesamten Seite und dem Benutzer. Der Promise-Modus implementiert normalerweise eine Methode namens then, um die entsprechende Rückruffunktion zu registrieren, wenn sich der Status ändert. Zum Beispiel das folgende Codebeispiel:

searchTwitter(term).then(filterResults).then(displayResults);
Nach dem Login kopieren

promise模式在任何时刻都处于以下三种状态之一:未完成(unfulfilled)、已完成(resolved)和拒绝(rejected)。以CommonJS Promise/A 标准为例,promise对象上的then方法负责添加针对已完成和拒绝状态下的处理函数。then方法会返回另一个promise对象,以便于形成promise管道,这种返回promise对象的方式能够支持开发人员把异步操作串联起来,如then(resolvedHandler, rejectedHandler); 。resolvedHandler 回调函数在promise对象进入完成状态时会触发,并传递结果;rejectedHandler函数会在拒绝状态下调用。

有了promise模式,我们可以重新实现上面的Twitter示例。为了更好的理解实现方法,我们尝试着从零开始构建一个promise模式的框架。首先需要一些对象来存储promise。

var Promise = function () {
    /* initialize promise */
  };
Nach dem Login kopieren

接下来,定义then方法,接受两个参数用于处理完成和拒绝状态。

Promise.prototype.then = function (onResolved, onRejected) {
   /* invoke handlers based upon state transition */
 };
Nach dem Login kopieren

同时还需要两个方法来执行理从未完成到已完成和从未完成到拒绝的状态转变。

Promise.prototype.resolve = function (value) {
   /* move from unfulfilled to resolved */
 };
 
 Promise.prototype.reject = function (error) {
   /* move from unfulfilled to rejected */
 };
Nach dem Login kopieren

现在搭建了一个promise的架子,我们可以继续上面的示例,假设只获取IE10的内容。创建一个方法来发送Ajax请求并将其封装在promise中。这个promise对象分别在xhr.onload和xhr.onerror中指定了完成和拒绝状态的转变过程,请注意searchTwitter函数返回的正是promise对象。然后,在loadTweets中,使用then方法设置完成和拒绝状态对应的回调函数。

function searchTwitter(term) {

  var url, xhr, results, promise;
  url = 'http://search.twitter.com/search.json?rpp=100&q=' + term;
  promise = new Promise();
  xhr = new XMLHttpRequest();
  xhr.open('GET', url, true);

  xhr.onload = function (e) {
    if (this.status === 200) {
      results = JSON.parse(this.responseText);
      promise.resolve(results);
    }
  };

  xhr.onerror = function (e) {
    promise.reject(e);
  };

  xhr.send();
  return promise;
}

function loadTweets() {
  var container = document.getElementById('container');
  searchTwitter('#IE10').then(function (data) {
    data.results.forEach(function (tweet) {
      var el = document.createElement('li');
      el.innerText = tweet.text;
      container.appendChild(el);
    });
  }, handleError);
}

Nach dem Login kopieren

到目前为止,我们可以把promise模式应用于单个Ajax请求,似乎还体现不出promise的优势来。下面来看看多个Ajax请求的并发协作。此时,我们需要另一个方法when来存储准备调用的promise对象。一旦某个promise从未完成状态转化为完成或者拒绝状态,then方法里对应的处理函数就会被调用。when方法在需要等待所有操作都完成的时候至关重要。

Promise.when = function () {
  /* handle promises arguments and queue each */
};
Nach dem Login kopieren

以刚才获取IE10和IE9两块内容的场景为例,我们可以这样来写代码:

var container, promise1, promise2;
container = document.getElementById('container');
promise1 = searchTwitter('#IE10');
promise2 = searchTwitter('#IE9');
Promise.when(promise1, promise2).then(function (data1, data2) {

  /* Reshuffle due to date */
  var totalResults = concatResults(data1.results, data2.results);
  totalResults.forEach(function (tweet) {
    var el = document.createElement('li');
    el.innerText = tweet.text;
    container.appendChild(el);
  });
}, handleError);

Nach dem Login kopieren

分析上面的代码可知,when函数会等待两个promise对象的状态发生变化再做具体的处理。在实际的Promise库中,when函数有很多变种,比如 when.some()、when.all()、when.any()等,读者从函数名字中大概能猜出几分意思来,详细的说明可以参考CommonJS的一个promise实现when.js。

除了CommonJS,其他主流的Javascript框架如jQuery、Dojo等都存在自己的promise实现。开发人员应该好好利用这种模式来降低异步编程的复杂性。我们选取Dojo为例,看一看它的实现有什么异同。

Dojo框架里实现promise模式的对象是Deferred,该对象也有then函数用于处理完成和拒绝状态并支持串联,同时还有resolve和reject,功能如之前所述。下面的代码完成了Twitter的场景:

function searchTwitter(term) {

  var url, xhr, results, def;
  url = 'http://search.twitter.com/search.json?rpp=100&q=' + term;
  def = new dojo.Deferred();
  xhr = new XMLHttpRequest();
  xhr.open('GET', url, true);

  xhr.onload = function (e) {
    if (this.status === 200) {
      results = JSON.parse(this.responseText);
      def.resolve(results);
    }
  };

  xhr.onerror = function (e) {
    def.reject(e);
  };

  xhr.send();
  return def;
}

dojo.ready(function () {
  var container = dojo.byId('container');
  searchTwitter('#IE10').then(function (data) {
    data.results.forEach(function (tweet) {
      dojo.create('li', {
        innerHTML: tweet.text
      }, container);
    });
  });
});

Nach dem Login kopieren

不仅如此,类似dojo.xhrGet方法返回的即是dojo.Deferred对象,所以无须自己包装promise模式。

var deferred = dojo.xhrGet({
  url: "search.json",
  handleAs: "json"
});

deferred.then(function (data) {
  /* handle results */
}, function (error) {
  /* handle error */
});

Nach dem Login kopieren

除此之外,Dojo还引入了dojo.DeferredList,支持开发人员同时处理多个dojo.Deferred对象,这其实就是上面所提到的when方法的另一种表现形式。

dojo.require("dojo.DeferredList");
dojo.ready(function () {
  var container, def1, def2, defs;
  container = dojo.byId('container');
  def1 = searchTwitter('#IE10');
  def2 = searchTwitter('#IE9');

  defs = new dojo.DeferredList([def1, def2]);

  defs.then(function (data) {
    // Handle exceptions
    if (!results[0][0] || !results[1][0]) {
      dojo.create("li", {
        innerHTML: 'an error occurred'
      }, container);
      return;
    }
    var totalResults = concatResults(data[0][1].results, data[1][1].results);

    totalResults.forEach(function (tweet) {
      dojo.create("li", {
        innerHTML: tweet.text
      }, container);
    });
  });
});

Nach dem Login kopieren

上面的代码比较清楚,不再详述。

说到这里,读者可能已经对promise模式有了一个比较完整的了解,异步编程会变得越来越重要,在这种情况下,我们需要找到办法来降低复杂度,promise模式就是一个很好的例子,它的风格比较人性化,而且主流的JS框架提供了自己的实现。所以在编程实践中,开发人员应该尝试这种便捷的编程技巧。需要注意的是,promise模式的使用需要恰当地设置promise对象,在对应的事件中调用状态转换函数,并且在最后返回promise对象。


Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage
Über uns Haftungsausschluss Sitemap
Chinesische PHP-Website:Online-PHP-Schulung für das Gemeinwohl,Helfen Sie PHP-Lernenden, sich schnell weiterzuentwickeln!