Javascript $resource `get` 函数如何在 AngularJS 中同步工作?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11966252/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How does the $resource `get` function work synchronously in AngularJS?
提问by cilphex
I was watching thisAngularJS tutorial describing how to hook into Twitter with an Angular resource. (Video tutorial) Here is the resource that is set up in the example controller:
我正在观看这个AngularJS 教程,该教程描述了如何使用 Angular 资源连接到 Twitter。(视频教程)这是示例控制器中设置的资源:
$scope.twitter = $resource('http://twitter.com/:action',
{action: 'search.json', q: 'angularjs', callback: 'JSON_CALLBACK'},
{get: {method: 'JSONP'}});
The tutorial shows that there are a couple ways to get data back from the resource using the get
call. The first method is by passing a callback to the get function. The callback will be called with the result after the ajax request returns:
本教程展示了使用get
调用从资源中取回数据的几种方法。第一种方法是将回调传递给 get 函数。ajax 请求返回后,将使用结果调用回调:
$scope.twitter.get(function(result) {
console.log('This was the result:', result);
});
I understand this method. It makes perfect sense to me. The resource represents a place on the web where you can get data, and get
simply makes an ajax call to a url, gets json back, and calls the callback function with the json. The result
param is that json.
我理解这个方法。这对我来说很有意义。资源代表网络上可以获取数据的地方,get
只需对 url 进行 ajax 调用,返回 json,并使用 json 调用回调函数。该result
参数是该JSON。
It makes sense to me because it seems obvious that this is an asynchronous call. That is, under the hood, the ajax call fires, and the code following the call isn't blocked, it continues to be executed. Then at some indeterminate point later on, when the xhr is successful, the callback function is called.
这对我来说很有意义,因为很明显这是一个异步调用。也就是说,在幕后,ajax 调用会触发,并且调用之后的代码不会被阻止,而是会继续执行。然后在稍后的某个不确定点,当 xhr 成功时,将调用回调函数。
Then the tutorial shows a different method that looks a lot simpler, but I don't understand how it works:
然后教程展示了一种看起来简单很多的不同方法,但我不明白它是如何工作的:
$scope.twitterResult = $scope.twitter.get();
I assume that the xhr underneath get
must be asynchronous, yet in this line we are assigning the return value of the get
call to a variable, as if it returned synchronously.
我假设下面的 xhrget
必须是异步的,但在这一行中,我们将get
调用的返回值分配给一个变量,就好像它是同步返回的一样。
Am I wrong for not understanding this? How is that possible? I think it's really neat that it works, I just don't get it.
我不理解这一点有错吗?这怎么可能?我认为它真的很好用,我只是不明白。
I understand that get
can return somethingwhile the xhr underneath it goes off and processes asynchronously, but if you follow the code example yourself, you will see that $scope.twitterResult
gets the actual twitter content before any subsequent lines are executed. For example, if you write console.log($scope.twitterResult)
immediately after that line, you will see the results from twitter logged in the console, not a temporary value that is replaced later on.
我知道当它下面的 xhr 关闭并异步处理时get
可以返回一些东西,但是如果你自己遵循代码示例,你会看到$scope.twitterResult
在执行任何后续行之前获取实际的 twitter 内容。例如,如果您console.log($scope.twitterResult)
在该行之后立即写入,您将看到来自 twitter 的结果记录在控制台中,而不是稍后替换的临时值。
More importantly, because this is possible, how can I write an Angular service that takes advantage of this same functionality? Besides ajax requests, there are other types of data stores requiring asynchronous calls that can be used in JavaScript which I would love to be able to write code for synchronously in this style. For example, IndexedDB. If I could wrap my head around how Angular's built-in resources are doing it, I would give it a shot.
更重要的是,因为这是可能的,我如何编写一个利用相同功能的 Angular 服务?除了 ajax 请求,还有其他类型的数据存储需要异步调用,可以在 JavaScript 中使用,我希望能够以这种方式同步编写代码。例如,IndexedDB。如果我能理解 Angular 的内置资源是如何做的,我会试一试。
回答by pkozlowski.opensource
$resource is not synchronous although this syntax might suggest that it is:
$resource 不是同步的,尽管此语法可能表明它是:
$scope.twitterResult = $scope.twitter.get();
What is going on here is that call to the AngularJS will, after call to twitter.get()
, return immediately with the result being an empty array. Then, when the async call is finished and real data arrives from the server, the array will get updated with data. AngularJS will simply keep a reference to an array returned and will fill it in when data are available.
这到底是怎么回事是调用AngularJS会,号召后twitter.get()
,其结果是空数组立即返回。然后,当异步调用完成并且真实数据从服务器到达时,数组将更新为 data。AngularJS 将简单地保留对返回的数组的引用,并在数据可用时填充它。
Here is the fragment of $resource implementation where the "magic" happens: https://github.com/angular/angular.js/blob/master/src/ngResource/resource.js#L372
这是“魔术”发生的 $resource 实现的片段:https: //github.com/angular/angular.js/blob/master/src/ngResource/resource.js#L372
This is described in the $resource documentationas well:
这在$resource 文档中也有描述:
It is important to realize that invoking a $resource object method immediately returns an empty reference (object or array depending on
isArray
). Once the data is returned from the server the existing reference is populated with the actual data. This is a useful trick since usually the resource is assigned to a model which is then rendered by the view. Having an empty object results in no rendering, once the data arrives from the server then the object is populated with the data and the view automatically re-renders itself showing the new data. This means that in most case one never has to write a callback function for the action methods.
重要的是要意识到调用 $resource 对象方法会立即返回一个空引用(对象或数组取决于
isArray
)。从服务器返回数据后,现有引用将填充实际数据。这是一个有用的技巧,因为通常资源被分配给一个模型,然后由视图呈现。拥有一个空对象会导致没有渲染,一旦数据从服务器到达,对象就会填充数据,并且视图会自动重新渲染以显示新数据。这意味着在大多数情况下,您永远不必为操作方法编写回调函数。
回答by Lars Bohl
$q can do this trick too. You can convert a normal object to a 'delayed value' using something like this:
$q 也可以做到这一点。您可以使用以下方法将普通对象转换为“延迟值”:
var delayedValue = function($scope, deferred, value) {
setTimeout(function() {
$scope.$apply(function () {
deferred.resolve(value);
});
}, 1000);
return deferred.promise;
};
and then use it in a controller, to get a similar effect to what $scope.twitter.get() does in the OP's example
然后在控制器中使用它,以获得与 $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']);
}]);