前面有說處處理angularjs中的異步的問題,在福瑞項目中我是經過邏輯判斷不停的調用方法判斷是否異步的按個函數已經執行完畢的。angularjs
這裏我們就來講下angularjs中的異步的問題,以及「正規的解決方法」編程
先聊一聊關於promise中的異步編程json
異步編程存在兩種形式,一種是單次執行模式,一種是監聽執行模式。$q是解決第一種模式下的問題,promise模式的異步編程可以很好的解決單次執行模式下的一些問題,再說白一點,promise不會產生新的東西只是一個語法糖幫你可以編出更加優雅的異步代碼api
Promise模式使用一個延期對象defer表明異步執行體,用promise表明回調執行體,defer能夠發送信息,promise能夠接受信息,而後執行響應的回調函數。數組
說到這,是否是能夠想到富瑞上面的那個問題能夠把它們放到promise裏進行鏈式調用了呢?咱們繼續往下說:promise
Promise是異步執行體和回調執行體之間的橋樑,這樣的好處是異步執行體和回調執行體這種模式很好的對異步動做和回調動做進行了解耦。由於你能夠在promise中好好的執行你的回調執行體,而只是接受一個defer發送來的參數。服務器
這裏仍是沒有很好的體現出promise模式的優點,而他真正的優點在於這種模式下擴充的api,。好比promise下的then方法,這種方法能夠很好地支持異步鏈式編程。這裏你可能還不瞭解,說下$q,$q是做爲angularJs中的一個服務而存在的,只是對promise模式下異步的一個簡單實現版(這裏想到了華勤項目中小馬哥用到的$q,當時還很差意思問這是啥!)關於$q的api你們能夠從網上百度下、這裏我就簡單的說下app
defer對象(延遲對象)能夠通$q.defer()獲取,下面是defer對象的api:異步
方法:異步編程
resolve(value):向promise對象異步執行體發送消息告訴他我已經成功完成任務,value即爲發送的消息。
reject(value): 向promise對象異步執行體發送消息告訴他我已經不可能完成這個任務了,value即爲發送的消息。
notify(value): 向promise對象異步執行體發送消息告訴他我如今任務完成的狀況,value即爲發送的消息。
這些消息發送完promise會調用現有的回調函數。
屬性:
promise即與這個defer對象的承諾對象。
從上能夠看出defer主要是用來發送消息的。
promise對象能夠經過defer.promise獲取,下面是promise對象的api:
方法:
then(successCallback,errorCallback,notifyCallback):參數爲不一樣消息下的不一樣回調函數,defer發送不一樣的消息執行不一樣的回調函數,消息做爲這些回調函數的參數傳遞。返回值爲回一個promise對象爲支持鏈式調用而存在。當第一個defer對象發送消息後,後面的promise對應的defer對象也會發送消息,可是發送的消息不同,無論第一個defer對象發送的是reject仍是resolve,第二個及其之後的都是發送的resolve,消息是可傳遞的。
catch(errorCallback):then(null,errorCallback)的縮寫。
finally(callback):至關於then(callback,callback)的縮寫,這個finally中的方法不接受參數,卻能夠將defer發送的消息和消息類型成功傳遞到下一個then中
defer():用來生成一個延遲對象 var defer =$q.defer();
reject():參數接收錯誤消息,至關於在回調函數中拋出一個異常,而後在下一個then中調用錯誤的回調函數。
all():參數接收爲一個promise數組,返回一個新的單一promise對象,當這些promise對象對應defer對象所有解決這個單一promise對象纔會解決,當這些promise對象中有一個被reject了,這個單一promise一樣的被reject了
when():接收第一個參數爲一個任意值或者是一個promise對象,其餘3個同promise的then方法,返回值爲一個promise對象。第一個參數若不是promise對象則直接運行success回調且消息爲這個對象,若爲promise那麼返回的promise其實就是對這個promise類型的參數的一個包裝而已,被傳入的這個promise對應的defer發送的消息,會被咱們when函數返回的promise對象所接收到。
對上面還有一個注意事項就是defer對象發送消息不會當即執行的,而是把要執行的代碼放到了rootScope的evalAsync隊列當中,當時scope.$apply的時候纔會被promise接收到這個消息。
這裏附上一份小馬哥在華勤上寫的一個代碼,我加了些註釋:
//請求服務器數據 function makeRequest($http,$q,url,params){ // $q 是內置服務,因此能夠直接使用 try{ var defered=$q.defer(); // 聲明延後執行,表示要去監控後面的執行 $http.get(url,params ) .success(function(data, status, headers) { // Do something successful defered.resolve(data); // 聲明執行成功,即http請求數據成功,能夠返回數據了 }) .error(function(data, status, headers) { // Handle the error defered.reject(status+data); // 聲明執行失敗,即服務器返回錯誤 }); return defered.promise; // 返回承諾,這裏並非最終數據,而是訪問最終數據的API }catch(error){ alert("鏈接服務發生意外錯誤"); } }
下面是對應的調用:
promise.then(function(data) { // 調用承諾API獲取數據 .resolve $scope.user = data; }, function(data) { // 處理錯誤 .reject $scope.user = {error: '用戶不存在!'}; });
最後來講明下關於實現angularjs中的同步請求的三種解決方法
解決方法一:
$http.get('url1').success(function (d1) { $http.get('url2').success(function (d2) { //處理邏輯 }); });
解決方法二:
then中的方法會按順序執行。
var app = angular.module('app',[]); app.controller('promiseControl',function($scope,$q,$http) { function getJson(url){ var deferred = $q.defer(); $http.get(url) .success(function(d){ d = parseInt(d); console.log(d); deferred.resolve(d); }); return deferred.promise; } getJson('json1.txt').then(function(){ return getJson('json2.txt'); }).then(function(){ return getJson('json1.txt'); }).then(function(){ return getJson('json2.txt'); }).then(function(d){ console.log('end'); }); });
解決方法三
$q.all方法第一個參數能夠是數組(對象)。在第一參數中內容都執行完後就會執行then中方法。第一個參數的方法的全部返回值會以數組(對象)的形式傳入。
var app = angular.module('app',[]); app.controller('promiseControl',function($scope,$q,$http) { $q.all({first: $http.get('json1.txt'),second: $http.get('json2.txt')}).then(function(arr){ console.log(arr); angular.forEach(arr,function(d){ console.log(d); console.log(d.data); }) }); });