Angularjs Promise 解決異步獲取數據致使return返回爲空的問題

最近在開發項目的時候。我在service中請求數據返回給控制器的時候,因爲數據是異步請求的,這裏須要知道javascript的運行環境是單線程的,一次只能執行一個任務,可是單線程壞處就是若是前一個任務執行時間較長就會致使整個頁面的阻塞,所以javascript提供了異步請求,使任務能夠不用等待上一個任務執行完成。但就是這個異步的請求,致使個人data數據還沒返回就已經return數據到控制層了,從而返回值爲空。javascript

goodsService

app.factory('goodsService', function($http,$q) {
    var goodsData=111;
    function get() {
        $http({
            method:'get',
            url:'test/goods.json'
        }).success(function(data,status,headers,config){
            console.log('get success...');
            console.log(goodsData);
            goodsData=data;
           return goodsData;

        }).error(function(data,status,headers,config){
            console.log('get error...');
        })
    }
    function set(data) {
        $http({
            method:'post',
            url:'test/goods.json'
        }).success(function(data,status,headers,config){
            goodsData=data;
            console.log('get success...');
            console.log(data);
        }).error(function(data,status,headers,config){
            console.log('get error...');
        })
    }
    return {
        set: set,
        get: get
    }
});

controller.js

$scope.goods=goodsService.get();
console.log('scope.goods='+$scope.goods);

圖片描述

固然不少人都有不少種解決辦法。好比說函數引用:java

$.get(/test/goods.json', function(data) {
  return data;
});

固然都是可行的。可是當處理比較複雜的多個異步進行的時候那就真是看的頭暈眼花。
所以Promise應運而生。json

Promise的身份之謎

Promise有兩部分:promise

  • Deferred定義工做單元,
    用來定義工做單元的開始,處理和結束三部分緩存

  • Promise接收Deferred返回的數據。
    有狀態和句柄。Promise 不一樣於回調的很重要的一個點是,你能夠在 Promise 狀態變成執行(resolved)以後追加處理句柄。這就容許你傳輸數據,而忽略它是否已經被應用獲取,而後緩存它,等等之類的操做,所以你能夠對數據執行操做,而無論它是否已經或者即將可用。app

在Angularjs使用Promise的時候須要用到內置服務$q。異步

  • $q服務受到Kris Kowal的Q庫的啓發,因此相似於那個庫,可是並無包含那個庫的所用功能。函數

  • $q是跟AngularJS的$rootScope模板集成的,因此在AngularJS中執行和拒絕都很快。 $qpost

  • promise是跟AngularJS模板引擎集成的,這意味着在視圖中找到任何Promise都會在視圖中被執行或者拒絕。
    $q實現了上面提到的全部的Deferred和Promise方法。url

$q.defer()提供給咱們一個建立Deferred對象的方法。這個Deffered對象有個promise屬性,這個屬性帶有6個方法:

  • resolve(value):用來執行deferred promise,value能夠爲字符串,對象等。

  • reject(value):用來拒絕deferred promise,value能夠爲字符串,對象等。

  • notify(value):獲取deferred promise的執行狀態,而後使用這個函數來傳遞它。

  • then(successFunc, errorFunc,notifyFunc):不管promise是成功了仍是失敗了,當結果可用以後,then都會馬上異步調用successFunc,或者'errorFunc',在promise被執行或者拒絕以前,notifyFunc可能會被調用0到屢次,以提供過程狀態的提示。

  • catch(errorFunc)

  • finally(callback)
    更加形象點。就好比說我如今遇到的這個問題。當個人goodsService請求商品數據的時候,我先用$q.defer()建立了一個deferred對象。而後經過該對象的promise屬性獲取到一個promise對象。這時我進行數據請求,定義請求成功和請求失敗的計劃分別是deferred.resolve(data)和deferred.reject()。而後將這個promise返回給請求service的控制層。控制層經過.then建立一個執行鏈,它容許咱們中斷基於更多功能的應用流程,能夠藉此導向不一樣的的結果,再來進行不一樣的操做。

goodsService

app.factory('goodsService', function($http,$q) {
    function get() {
        var deferred=$q.defer();
        var promise=deferred.promise;
        $http({
            method:'get',
            url:'test/goods.json'
        }).success(function(data,status,headers,config){
            deferred.resolve(data);//執行成功
        }).error(function(data,status,headers,config){
            deferred.reject();//執行失敗
        })
        console.log('return promise');
        return promise;
    }
    function set(data) {
        $http({
            method:'post',
            url:'test/goods.json'
        }).success(function(data,status,headers,config){
            deferred.resolve(data);//執行成功
            console.log('get success...');
        }).error(function(data,status,headers,config){
            console.log('get error...');
        })
    }
    return {
        set: set,
        get: get
    }
});

productListCtrl

goodsService.get().then(function(result){
    console.log('goodsService get successed');
    $scope.goods=result;
    console.log('scope.goods1='+$scope.goods);
    },function(){
    console.log('goodsService get error');
    });
    console.log('scope.goods2='+$scope.goods);
});

圖片描述

數據顯示正常。也能夠從下面的scope.goods1和scope.goods2看出promise的特性,在等待返回選擇不一樣計劃的時候不會阻塞其餘的任務執行。

相關文章
相關標籤/搜索