參考:
http://www.infoq.com/cn/news/2011/09/js-promise
http://www.cnblogs.com/rubylouvre/p/3495286.html
https://segmentfault.com/a/1190000000684654
目的:為了降低異步編程的復雜性
promise模式在任何時刻都處於以下三種狀態之一:未完成(unfulfilled)、已完成(resolved)和拒絕(rejected)
1 //構建promise模式的框架 2 var Promise = function(){ 3 // initialize promise 4 } 5 //定義then方法——接受兩個參數用於處理完成和拒絕狀態 6 Promise.prototype.then = function(onResolved, onRejected){ 7 //invoke handlers based upon state transition 8 } 9 //兩個方法來執行從未完成到已完成和從未完成到拒絕的狀態轉變 10 Promise.prototype.resolve = function(value){ 11 //未完成----->已完成 12 } 13 Promise.prototype.reject = function(error){ 14 //未完成------>拒絕 15 }
現在搭建了一個promise的架子,我們可以繼續上面的示例,假設只獲取IE10的內容。創建一個方法來發送Ajax請求並將其封裝在promise中。這個promise對象分別在xhr.onload和xhr.onerror中指定了完成和拒絕狀態的轉變過程,請注意searchTwitter函數返回的正是promise對象。然后,在loadTweets中,使用then方法設置完成和拒絕狀態對應的回調函數。
即then接收兩個參數,成功則調用第一個,否則調用第二個
1 function search(term){ 2 var url,xhr,results,promise; 3 url = "http://search.twitter.com/search.json?rpp=100&q="+term; 4 promise = new Promise(); 5 xhr = new XMLHttpRequest(); 6 xhr.open('GET',url,true); 7 8 xhr.onload = function(e){ 9 if(this.status === 200){ 10 results = JSON.parse(this.responseText); 11 promise.resolve(results); 12 } 13 }; 14 15 xhr.onerror = function(e){ 16 promise.reject(e); 17 }; 18 19 xhr.send(); 20 return promise; 21 } 22 23 function loadTweets(){ 24 var container = doucment.getElementById('container'); 25 seach("#IE10").then(function(data){ 26 data.results.forEach(function(tweet){ 27 var el = document.createElement('li'); 28 el.innerText = tweet.text; 29 container.appendChild(el); 30 }); 31 32 },handleError); 33 }
到目前為止,我們可以把promise模式應用於單個Ajax請求,似乎還體現不出promise的優勢來。下面來看看多個Ajax請求的並發協作。此時,我們需要另一個方法when來存儲准備調用的promise對象。一旦某個promise從未完成狀態轉化為完成或者拒絕狀態,then方法里對應的處理函數就會被調用。when方法在需要等待所有操作都完成的時候至關重要。
1 Promise.when = function(){ 2 //handle promises arguments and queue each 3 } 4 var container, promise1, promise2; 5 container = document.getElementById('container'); 6 promise1 = search('#IE10'); 7 promise2 = search('#IE9'); 8 Promise.when(promise1,promise2).then(function(data1,data2){ 9 //Reshuffle due to date 10 var totalResults = concatResults(data1.results, data2.results); 11 totalResults.forEach(function(tweet){ 12 var el = document.createElement('li'); 13 el.innerText = tweet.text; 14 container.appendChild(el); 15 }); 16 },handleError);
