$ resource`get`函数如何在AngularJS中同步工作?

cil*_*hex 43 javascript angularjs

我正在观看这个 AngularJS教程,教程描述了如何使用Angular资源挂钩到Twitter.(视频教程)以下是示例控制器中设置的资源:

$scope.twitter = $resource('http://twitter.com/:action',
    {action: 'search.json', q: 'angularjs', callback: 'JSON_CALLBACK'},
    {get: {method: 'JSONP'}});
Run Code Online (Sandbox Code Playgroud)

该教程显示有几种方法可以使用get调用从资源中恢复数据.第一种方法是将回调传递给get函数.在ajax请求返回后,将使用结果调用回调:

$scope.twitter.get(function(result) {
    console.log('This was the result:', result);
});
Run Code Online (Sandbox Code Playgroud)

我理解这种方法.这对我来说非常有意义.资源代表Web上可以获取数据的位置,get只需对URL进行ajax调用,返回json,并使用json调用回调函数.这个result参数是json.

这对我来说很有意义,因为很明显这是一个异步调用.也就是说,在引擎盖下,ajax调用会触发,并且调用后的代码不会被阻止,它会继续执行.然后在稍后的某个不确定点,当xhr成功时,调用回调函数.

然后教程显示了一个看起来更简单的不同方法,但我不明白它是如何工作的:

$scope.twitterResult = $scope.twitter.get();
Run Code Online (Sandbox Code Playgroud)

我假设下面的xhr get必须是异步的,但在这一行中我们将get调用的返回值赋给变量,就像它同步返回一样.

不理解这个我错了吗?怎么可能?我觉得它很有效,但是我觉得它不行.

我的理解是get可以返回的东西,而在其下方XHR熄灭和流程异步,但如果你自己遵循的代码示例,你会看到,$scope.twitterResult在执行任何后续行之前得到的实际Twitter的内容.例如,如果您console.log($scope.twitterResult)在该行之后立即写入,您将在控制台中看到来自twitter的结果,而不是稍后替换的临时值.

更重要的是,因为这是可能的,我如何编写利用相同功能的Angular服务?除了ajax请求之外,还有其他类型的数据存储需要可以在JavaScript中使用的异步调用,我希望能够以这种方式同步编写代码.例如,IndexedDB.如果我能够了解Angular的内置资源是如何做到的,我会试一试.

pko*_*rce 63

$ resource不是同步的,尽管这种语法可能表明它是:

$scope.twitterResult = $scope.twitter.get();
Run Code Online (Sandbox Code Playgroud)

这里发生的是调用AngularJS后twitter.get(),会立即返回结果为空数组.然后,当异步调用完成并且实际数据从服务器到达时,阵列将更新数据.AngularJS将简单地保留对返回的数组的引用,并在数据可用时填充它.

以下是$ magic实现的片段,其中发生了"魔术":https://github.com/angular/angular.js/blob/master/src/ngResource/resource.js#L372

这也在$ resource文档中描述:

重要的是要意识到调用$ resource对象方法会立即返回一个空引用(取决于对象或数组isArray).从服务器返回数据后,将使用实际数据填充现有引用.这是一个有用的技巧,因为通常将资源分配给模型,然后由视图呈现.具有空对象导致无渲染,一旦数据从服务器到达,则对象用数据填充,并且视图自动重新呈现其自身显示新数据.这意味着在大多数情况下,永远不必为动作方法编写回调函数.

  • 是的,这对我来说很有意义.对我来说没有意义的是,这里的`console.log`行不打印空引用,它打印一个来自twitter的实际结果:`$ scope.twitterResult = $ scope.twitter.get();`` console.log('result',$ scope.twitterResult);`如何在下一行代码之前填充数据?另外,感谢参考. (4认同)
  • 在console.log()上进行中继,因为我看到一些奇怪的效果,其中console.log和打印数组得到更新(基本上有时日志会获取更改并显示它们!).要查看发生了什么,请尝试以下操作:console.log(angular.copy($ scope.twitterResult)),因此请确保从通话中打印一个值.这是关于计时真的,你可能会在控制台有机会打印任何东西之前从$ resource获得结果...... (4认同)
  • 你知道吗 - 你是对的.`console.log`应该受到指责.如果我这样做,我得到一个空对象:`alert(JSON.stringify($ scope.twitterResult));`谢谢你的帮助! (3认同)
  • 我只是想在这里弹出并指出使用AngularJS 1.2不再发生模板中的promises自动解包.如果你只是将$ http,$ resource等的promises直接分配给$ scope变量,那么当你在视图中引用它们时,不要指望它们能够正常工作.他们不会.有关详细信息,请参阅其迁移文档:http://docs.angularjs.org/guide/migration (3认同)

Lar*_*ohl 5

$ q也可以做到这一点.您可以使用以下内容将普通对象转换为"延迟值":

var delayedValue = function($scope, deferred, value) {
    setTimeout(function() {
        $scope.$apply(function () {
            deferred.resolve(value);
        });
    }, 1000);
    return deferred.promise;
};
Run Code Online (Sandbox Code Playgroud)

然后在控制器中使用它,以获得与$ scope.twitter.get()在OP示例中所做的类似的效果

angular.module('someApp', [])
.controller('someController', ['$scope', '$q', function($scope, $q) {
  var deferred = $q.defer();
  $scope.numbers = delayedValue($scope, deferred, ['some', 'numbers']);
}]);
Run Code Online (Sandbox Code Playgroud)