JavaScript异步编程的Promise模式
参考:
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);