亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

詳解JavaScript異步編程中jQuery的promise對象的作用

2019-11-20 10:10:22
字體:
來源:轉載
供稿:網友

Promise, 中文可以理解為愿望,代表單個操作完成的最終結果。一個Promise擁有三種狀態:分別是unfulfilled(未滿足的)、fulfilled(滿足的)、failed(失敗的),fulfilled狀態和failed狀態都可以被監聽。一個愿望可以從未滿足狀態變為滿足或者失敗狀態,一旦一個愿望處于滿足或者失敗狀態,其狀態將不可再變化。這種“不可改變”的特性對于一個Promise來說非常的重要,它可以避免Promise的狀態監聽器修改一個Promise的狀態導致別的監聽器的行為異常。例如:一個監聽fulfilled狀態的監聽器把Promise的狀態修改為failed,那么將觸發failed狀態的監聽器,而如果一個failed狀態監聽器又把Promise的狀態設置為fulfilled,那么又將觸發fulfilled狀態的監聽器,這樣將導致死循環。另外一種理解Promise這種特性的方式是把Promise看成是javascript中的primative類型的變量,這種變量可以被傳入被調用的函數中,但是不可以被調用函數所改變。

每一個Promise對象都有一個方法:then(fulfilledHandler, errorHandler, progressHandler),用于監聽一個Promise的不同狀態。fulfilledHandler用于監聽fulfilled事件,errorHandler用于監聽failed事件,progressHandler用于監聽progress事件。一個Promise不強制實現progress狀態的事件監聽(jQuery的Deferred就是一個Promise的實現,但沒有實現對progress狀態事件的處理)。

then(...)函數中的fulfilledHandler和errorHandler的返回值是一個新的Promise對象, 以便能夠鏈式調用then(...)函數。每一個回調函數在正常情況下返回的是處于fulfilled狀態的Promise,如果該回調函數返回錯誤值,那么返回的Promise狀態將會變為failed。

promise在異步編程中的作用

異步模式在web編程中變得越來越重要,對于web主流語言Javascript來說,這種模式實現起來不是很利索,為此,許多Javascript庫(比如 jQuery和Dojo)添加了一種稱為promise的抽象(有時也稱之為deferred)。通過這些庫,開發人員能夠在實際編程中使用 promise模式。
隨著Web 2.0技術的深入,瀏覽器端承受了越來越多的計算壓力,所以“并發”具有積極的意義。對于開發人員來說,既要保持頁面與用戶的交互不受影響,又要協調頁面與異步任務的關系,這種非線性執行的編程要求存在適應的困難。先拋開頁面交互不談,我們能夠想到對于異步調用需要處理兩種結果――成功操作和失敗處理。在成功的調用后,我們可能需要把返回的結果用在另一個Ajax請求中,這就會出現“函數連環套”的情況。這種情況會造成編程的復雜性??纯聪旅娴拇a示例(基于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); }

上面的代碼其功能是獲取Twitter中hashtag為IE10和IE9的內容并在頁面中顯示出來。這種嵌套的回調函數難以理解,開發人員需要仔細分析哪些代碼用于應用的業務邏輯,而哪些代碼處理異步函數調用的,代碼結構支離破碎。錯誤處理也分解了,我們需要在各個地方檢測錯誤的發生并作出相應的處理。

為了降低異步編程的復雜性,開發人員一直尋找簡便的方法來處理異步操作。其中一種處理模式稱為promise,它代表了一種可能會長時間運行而且不一定必須完整的操作的結果。這種模式不會阻塞和等待長時間的操作完成,而是返回一個代表了承諾的(promised)結果的對象。

考慮這樣一個例子,頁面代碼需要訪問第三方的API,網絡延遲可能會造成響應時間較長,在這種情況下,采用異步編程不會影響整個頁面與用戶的交互。promise模式通常會實現一種稱為then的方法,用來注冊狀態變化時對應的回調函數。比如下面的代碼示例:

searchTwitter(term).then(filterResults).then(displayResults);

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 */  };

接下來,定義then方法,接受兩個參數用于處理完成和拒絕狀態。

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

同時還需要兩個方法來執行理從未完成到已完成和從未完成到拒絕的狀態轉變。

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

現在搭建了一個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);}

到目前為止,我們可以把promise模式應用于單個Ajax請求,似乎還體現不出promise的優勢來。下面來看看多個Ajax請求的并發協作。此時,我們需要另一個方法when來存儲準備調用的promise對象。一旦某個promise從未完成狀態轉化為完成或者拒絕狀態,then方法里對應的處理函數就會被調用。when方法在需要等待所有操作都完成的時候至關重要。

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

以剛才獲取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);

分析上面的代碼可知,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);    });  });});

不僅如此,類似dojo.xhrGet方法返回的即是dojo.Deferred對象,所以無須自己包裝promise模式。

var deferred = dojo.xhrGet({  url: "search.json",  handleAs: "json"});deferred.then(function (data) {  /* handle results */}, function (error) {  /* handle error */});

除此之外,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);    });  });});

上面的代碼比較清楚,不再詳述。

說到這里,讀者可能已經對promise模式有了一個比較完整的了解,異步編程會變得越來越重要,在這種情況下,我們需要找到辦法來降低復雜度,promise模式就是一個很好的例子,它的風格比較人性化,而且主流的JS框架提供了自己的實現。所以在編程實踐中,開發人員應該嘗試這種便捷的編程技巧。需要注意的是,promise模式的使用需要恰當地設置promise對象,在對應的事件中調用狀態轉換函數,并且在最后返回promise對象。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
日韩在线播放一区| 久久久久久亚洲精品不卡| 麻豆乱码国产一区二区三区| 欧美激情综合亚洲一二区| 91久久精品国产91性色| 日韩av免费在线| 亚洲国产中文字幕久久网| 欧美极品少妇xxxxⅹ免费视频| 精品国产欧美一区二区三区成人| 92版电视剧仙鹤神针在线观看| 久久久久久久一区二区| 国产在线a不卡| 欧美大片免费观看在线观看网站推荐| 成人精品一区二区三区电影免费| 亚洲国产精品yw在线观看| 九九热99久久久国产盗摄| 国产成人精品亚洲精品| 777777777亚洲妇女| 亚洲九九九在线观看| 亚洲va欧美va国产综合剧情| 精品久久久久久中文字幕一区奶水| 综合欧美国产视频二区| 51精品在线观看| 青青在线视频一区二区三区| 色先锋资源久久综合5566| 久久精品视频在线观看| 97不卡在线视频| 欧美日韩一区免费| 美女撒尿一区二区三区| 亚洲乱码国产乱码精品精| 日韩欧美国产黄色| 黑人狂躁日本妞一区二区三区| 国产日产亚洲精品| www亚洲欧美| 欧美黑人性猛交| 久久精品视频中文字幕| 亚洲精品小视频在线观看| 欧美大荫蒂xxx| 亚洲精品v天堂中文字幕| 国产精品偷伦一区二区| 91久久精品国产91性色| 中文字幕日韩高清| 国产伦精品一区二区三区精品视频| 日韩欧美中文字幕在线观看| 国产精品丝袜白浆摸在线| 久久色免费在线视频| 国产精品男人爽免费视频1| 久久九九国产精品怡红院| 国产精品丝袜一区二区三区| 精品国产美女在线| 亚洲第一网站免费视频| 91精品综合久久久久久五月天| 中文字幕日韩精品在线| 日韩在线播放视频| 精品国产一区二区三区在线观看| 国产日韩在线看片| 久久天天躁狠狠躁夜夜躁| 国产亚洲美女精品久久久| 亚洲欧洲第一视频| 亚洲精品国产精品国自产在线| 精品国产乱码久久久久酒店| 隔壁老王国产在线精品| 国产视频精品xxxx| 成人免费高清完整版在线观看| 日韩欧美在线播放| 欧美视频在线观看免费| 日韩中文字幕第一页| 中国日韩欧美久久久久久久久| 国内精品视频久久| 国产精品人人做人人爽| 97超级碰碰人国产在线观看| 国模叶桐国产精品一区| 91麻豆国产语对白在线观看| 亚洲男子天堂网| 久久韩国免费视频| 国产成人精品久久| 国产日本欧美一区二区三区在线| 亚洲精品国精品久久99热一| 尤物九九久久国产精品的特点| 国产成人精品a视频一区www| 欧美午夜精品久久久久久浪潮| 日韩在线免费观看视频| 国产精品视频白浆免费视频| 96国产粉嫩美女| 色视频www在线播放国产成人| 国产丝袜视频一区| 日韩av在线高清| 永久免费看mv网站入口亚洲| 热久久美女精品天天吊色| 日韩中文字幕在线精品| 92国产精品视频| 成人欧美一区二区三区黑人孕妇| 国产亚洲精品美女| 91av在线免费观看| 日韩视频在线一区| 欧美激情视频网址| 欧美日韩国产综合视频在线观看中文| 精品国产一区二区三区久久狼黑人| 欧美激情国产精品| 日韩中文字幕在线看| www.久久久久久.com| 国产欧美日韩亚洲精品| 中文字幕精品网| 亚洲片在线资源| 久久精品国产一区| 91香蕉嫩草神马影院在线观看| 国产精品热视频| 97精品免费视频| 亚洲欧美一区二区三区情侣bbw| 国产91精品网站| 欧美最顶级的aⅴ艳星| 欧美乱大交xxxxx另类电影| 狠狠躁18三区二区一区| 亚洲视频电影图片偷拍一区| 欧美日韩中文字幕日韩欧美| 国产成人精品在线| 亚洲精品自产拍| 成人激情视频在线| 亚洲精品色婷婷福利天堂| 成人欧美在线观看| 欧美精品在线观看| 欧美在线播放视频| 26uuu久久噜噜噜噜| 国产免费一区二区三区在线观看| 亚洲高清免费观看高清完整版| 亚洲免费影视第一页| 国产欧美精品一区二区| 91sao在线观看国产| 亚洲乱码一区av黑人高潮| 亚洲男人天堂古典| 日韩中文字幕免费视频| xx视频.9999.com| 九九精品在线视频| 亚洲а∨天堂久久精品喷水| 欧美华人在线视频| 欧美激情啊啊啊| 日韩av在线免播放器| 久久国产精品久久久久| 亚洲国产一区二区三区四区| 欧美一级免费看| 欧美精品一区二区免费| 永久免费毛片在线播放不卡| 国产a∨精品一区二区三区不卡| 亚洲图片在区色| 国产精品久久久久久一区二区| 日本欧美精品在线| 色婷婷综合久久久久中文字幕1| 亚洲网站在线看| 国产精品欧美一区二区三区奶水| 亚洲日韩欧美视频一区| 国模gogo一区二区大胆私拍| 另类专区欧美制服同性| 国产精品免费视频久久久| 日韩欧美在线字幕| 久久久久久伊人| 久久综合久久八八| 91美女片黄在线观看游戏| 久久av在线播放| 欧美日韩国产精品一区| 中文字幕日韩免费视频| 久久久www成人免费精品张筱雨| 在线播放亚洲激情| 久久精品视频免费播放| 国产精品丝袜久久久久久不卡|