43 votes

Comment la fonction $ resource `get` fonctionne-t-elle de manière synchrone dans AngularJS?

Je regardais ce AngularJS tutoriel décrivant comment raccorder sur Twitter avec des angles de ressources. (Tutoriel vidéo) Ici est la ressource qui est mis en place dans l'exemple de contrôleur:

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

Le tutoriel montre qu'il y a deux manières de récupérer des données à partir de la ressource à l'aide de l' get appel. La première méthode est de faire passer un rappel à la fonction get. Le callback sera appelé avec le résultat après la requête ajax retourne:

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

Je comprends que cette méthode. Il est parfaitement logique pour moi. La ressource représente un endroit sur le web où vous pouvez obtenir les données, et get simplement fait un appel ajax vers une url, obtient json en arrière, et appelle la fonction de rappel avec le json. L' result param est que json.

Il fait sens pour moi car il semble évident que c'est un appel asynchrone. C'est, sous le capot, l'appel ajax feux, et le code qui suit l'appel n'est pas bloqué, il continue à être exécutées. Puis à un moment indéterminé plus tard, quand le xhr est couronnée de succès, la fonction de rappel est appelée.

Puis le tutoriel montre une autre méthode qui ressemble beaucoup plus simple, mais je ne comprends pas comment il fonctionne:

$scope.twitterResult = $scope.twitter.get();

Je suppose que le xhr sous get doit être asynchrone, pourtant, dans cette ligne, nous sommes de l'affectation de la valeur de retour de la get appel à une variable, comme si elle revenait de façon synchrone.

Je suis mal pour ne pas comprendre cela? Comment est-ce possible? Je pense que c'est vraiment bien que ça fonctionne, je n'ai tout simplement pas l'obtenir.

Je comprends qu' get pouvez revenir à quelque chose tout en le xhr dessous, il s'en va et les processus de manière asynchrone, mais si vous suivez l'exemple de code vous-même, vous verrez qu' $scope.twitterResult obtient le réel contenu twitter avant les lignes suivantes sont exécutées. Par exemple, si vous écrivez console.log($scope.twitterResult) immédiatement après cette ligne, vous verrez les résultats de twitter enregistré dans la console, pas une valeur temporaire qui est remplacé plus tard.

Plus important encore, parce que c'est possible, comment puis-je écrire Angulaire de service qui prend avantage de cette même fonctionnalité? En plus des requêtes ajax, il existe d'autres types de banques de données nécessitant des appels asynchrones qui peuvent être utilisés en JavaScript, j'aimerais être capable d'écrire du code synchrone dans ce style. Par exemple, IndexedDB. Si je pouvais envelopper ma tête autour de la façon dont Angulaire intégrée des ressources sont en train de faire, j'aimerais donner un coup de feu.

63voto

pkozlowski.opensource Points 52557

$ressource n'est pas synchrone, bien que cette syntaxe peut penser que c'est:

$scope.twitterResult = $scope.twitter.get();

Ce qui se passe ici est que l'appel à la AngularJS, après l'appel à l' twitter.get(), de revenir immédiatement, le résultat étant un tableau vide. Ensuite, lors de l'appel asynchrone est terminée et les données réelles arrive sur le serveur, le tableau sera mis à jour avec les données. AngularJS va tout simplement de conserver une référence à un tableau retourné et le remplir lorsque les données sont disponibles.

Voici le fragment de dollars de ressources de mise en œuvre où la "magie" qu'il se passe: https://github.com/angular/angular.js/blob/master/src/ngResource/resource.js#L372

Ceci est décrit dans le $de ressources documentaires ainsi:

Il est important de réaliser que l'invocation d'une $objet de la ressource méthode retourne immédiatement un vide de référence (objet ou d'un tableau en fonction de isArray). Une fois les données renvoyées par le serveur de la référence existante est rempli avec les données réelles. C'est une astuce utile car, généralement, la ressource est affectée à un modèle qui est ensuite rendue par la vue. Avoir un objet vide résultats en aucun rendu, une fois que les données arrive sur le serveur, puis l'objet est rempli avec les données et de les afficher automatiquement re-rend lui-même montrant les nouvelles données. Cela signifie que dans la plupart des cas on n'a jamais à écrire une fonction de rappel pour les méthodes d'action.

5voto

Lars Bohl Points 349

$ q peut faire cette astuce aussi. Vous pouvez convertir un objet normal en une 'valeur différée' en utilisant quelque chose comme ceci:

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

puis utilisez-le dans un contrôleur pour obtenir un effet similaire à ce que fait $ scope.twitter.get () dans l'exemple du PO

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X