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的特性,在等待返回选择不一样计划的时候不会阻塞其余的任务执行。

相关文章
相关标签/搜索