如何在服务中使用异步库?

How to use async library in a service?

我正在尝试在我的服务中使用异步库。最终我计划进行一系列 $resource.query() 调用并将结果传递到阶梯上。

我 运行 遇到的问题是让我的 console.log() 等待异步系列完成。如何设置我的 async_service.async_func() 调用以使其异步,以便它在运行之前等待我的所有控制器函数完成?

  angular.module('app.services').factory('async_service', ['$resource',
  function($resource) {

 async_func:function(){

                return async.series([
                    function(callback){
                        //will do  a $resource.query() call eventually
                        callback(null, 'one');
                    },
                    function(callback){
                        //will do  a $resource.query() call eventually
                        callback(null, 'two');
                    }
                ],
                // optional callback
                return function(err, results){
                    return results;
                });
        }
}]);


angular.module('app.controllers', []) .controller('AppCtrl', ['$scope','async_service', function($scope, async_service) {

    var v = async_service.async_func();
    console.log(v);  //should be ['one', 'two'] but getting undefined

}]);

您的 console.log 打印输出需要等到 async.series 中的所有调用都完成。更改您的函数调用以获取回调,并在完成后打印 return 值:

async_func:function(cb) {

            return async.series([
                function(callback){
                    //will do  a $resource.query() call eventually
                    callback(null, 'one');
                },
                function(callback){
                    //will do  a $resource.query() call eventually
                    callback(null, 'two');
                }
            ],
            // optional callback
            function(err, results){
                return cb(err, results);
            });
    }
}]);

async_service.async_func(function(err, results) {
   if (!err)
       console.log(results);
})

更好的方法是使用 $q 它是 angular 的承诺系统。如果您使用它,则不需要另一个第三方依赖项的额外膨胀。

您的服务将是:

angular.module('app.services').factory('async_service', ['$resource', '$q',
    function($resource, $q) {
        return {
            async_func: function() {

                return $q.all(['one','two', this.hitApi()]);
            },
            hitApi: function () {
                /*
                    Simulate api call, 
                    $timeout returns a promise which is resolved when the timeout is met.
                    Same as $http
                */
                return $timeout(function(){ return 'three'}, 1000);
            }
        }
    }
]);

并将其用作

async_service.async_func().then(function (v) {
    /*
        .then() here will be called once all values/promises passed to $q.all have been resolved.
        If it receieves a promise it will wait untill those promises have been resolved.
        This would make it even easier if yo wish to do network calls as they return promises.
    */
    console.log(v);  //Will be ['one', 'two'] 
});

有一个警告需要理解。 $q.all 不会执行函数。它只是将价值包装在一个承诺中。如果该值恰好已经是一个承诺,它将在解决自身之前等待它解决。这就是我添加 hitApi() 方法的原因,这样您就可以看到如何实现该行为。还要注意控制器中的 .then() 如何在触发前等待超时完成。

参见fiddle:http://jsfiddle.net/rjLshbz5/1/ 查看文档:https://docs.angularjs.org/api/ng/service/$q


编辑:你的初始服务也不会有 运行 无论如何它会抛出语法错误。

这本来是你的冒犯点(减去你服务中缺失的 return {} 部分,但我猜这是将代码复制到 SO 中的错误):

            // optional callback
            return function(err, results){
                return results;
            });

JavaScript 不是这样的。您不能在该上下文中使用 return 关键字。您将变量传递给一个方法,async.series,第一个是数组,第二个是回调,一旦您在每个数组函数中调用 done 回调就完成。

async.series 没有 return 值。我不能,因为它对数组方法的执行是异步的。