访问通过Factory启动的变量,该变量启动异步请求

时间:2014-01-21 19:42:44

标签: javascript angularjs asynchronous

我有一个工厂发送POST请求以获取一些JSON键值对:

.factory('Rest', ['$resource',
function($resource) {

    // returns JSON key-value pairs, e.g. "{'foo', 'bar'}"
    return $resource('rest/get', {}, {
        get: {
            method: 'POST'
        }
    });

}])

我有另一家工厂打算接触控制器,以便根据其密钥访问键值对:

.factory('Pairs', ['Rest',
function(Rest) {

    var pairs;

    Rest.get(function(response) {
        pairs = response;
    });

    return {
        get: function(key) {
            return pairs[key];
        }
    };

}])

问题在于,当我调用Pairs.get('foo')时,pairs工厂的Pairs对象尚未初始化(因为Rest.get是异步的),因此结果在TypeError: Cannot read property 'foo' of undefined

.controller('AnyController', ['Pairs',
function (Pairs) {

    console.log(Pairs.get('foo')); // error

}])

知道如何解决这个问题吗?

2 个答案:

答案 0 :(得分:3)

正如您在问题中所述,Rest.get是异步的,因此您的Pairs.get也必须是异步的。您可以按以下方式实现它:

.factory('Pairs', ['Rest', '$q',
function(Rest, $q) {

var pairs;
var deferredList = [];

Rest.get(function(response) {
    pairs = response;
    angular.forEach(deferredList, function(o) {
        o.deferred.resolve(pairs[o.key]); // resolve saved defer object
    });
    deferredList = null; // we don't need the list anymore
});

return {
    get: function(key) {
        if (pairs) {
            return $q.when(pairs[key]); // make immediate value as a promise
        }

        var deferred = $q.defer(); // create a deferred object which will be resolved later
        deferredList.push({ // save both key and deferred object for later
            key: key,
            deferred: deferred
        });
        return deferred.promise;
    }
};

}])

然后像这样使用它:

Pairs.get('foo').then(function(value) {
    console.log(value);
});

答案 1 :(得分:1)

您希望将异步函数包装在promise中。这是我做类似事情的方式。 注意:如果需要,safeApply会触发$ digest循环,以便angular可以对它可能正在观察的任何数据更改做出反应。

 var safeApply = function (scope, fn) {
                    if (scope.$$phase || scope.$root.$$phase) { 
                        fn(); 
                    } else {  
                        scope.$apply(fn); 
                    }
                };

ret.getAll = function(type) {
    var deferred = $q.defer();
    var where = "apm_type = '" + type + "'";

    query(type, where, function(err, response) {
        var objs = [];
        if (err) {
            safeApply($rootScope, function() { deferred.reject(err);});
        } else {
            safeApply($rootScope, function() { deferred.resolve(response);});
        }

    }); 
    return deferred.promise;
};