请原谅我的无知,我是 Angular 和 JavaScript 的新手。 我读过, promise 使调用异步服务更加优雅,但我无法找到任何有关如何使我的服务异步的文档。
最佳答案
如果您只是简单地包装对 $http
的调用,那么您不需要做任何额外的工作。所有 $http
调用都会返回一个 Promise,因此您只需传递该 Promise,您的 API 将是异步且基于 Promise 的。
function MyService($http){
this.$http = $http;
}
MyService.prototype = {
getContacts: function(){
//$http returns a promise already,
// so just pass it along
return $http.get('/api/contacts');
}
};
angular.service('myService', MyService);
//Later on in some controller
function MyController(myService){
var _this = this;
//getContacts() returns the promise
// from $http
myService.getContacts()
.success(function(contacts){
_this.contacts = contacts;
});
}
但是...
如果您想创建一个异步执行代码的普通 API,那么您可以将其包装在 Promise 中,就像文档中的示例一样。
JavaScript 是 basically*单线程,这意味着它使用异步代码的执行队列。执行会从上到下进行,每当停止时,队列就会按顺序清空。
当您调用诸如 setTimeout
或 setInterval
之类的内容时,它只是将该代码放入队列中,以便在当前线程到达时执行,但事实并非如此。 t 在后台发生。
您可以通过打开浏览器控制台并在其中键入以下代码来自行测试:
setTimeout(function(){ console.log("I'm first!"); }, 0);
console.log("Nope, I am!");
即使我将超时设置为 0
毫秒,但这并不意味着它会立即执行。这意味着它将被放入队列中,一旦所有其他代码完成就立即运行。
终于
不要将 Promise 视为严格用于管理异步调用。它们是满足某些先决条件后执行代码的模式。碰巧,最流行的前提条件是通过 AJAX 进行异步 I/O。
但是该模式是管理任何必须等待一定数量先决条件的操作的好方法。
为了真正理解这一点,请查看这个小片段,它使用 Promise 来确定用户何时连续单击按钮超过 5 次。
(function() {
var app = angular.module('promise-example', []);
function PromiseBasedCounter($q, $timeout) {
this.$q = $q;
this.$timeout = $timeout;
this.counter = 0;
this.counterDef = $q.defer();
}
PromiseBasedCounter.$inject = ['$q', '$timeout'];
PromiseBasedCounter.prototype = {
increment: function() {
var _this = this;
//$timeout returns a promise, so we can
// just pass that along. Whatever is returned
// from the inner function will be the value of the
// resolved promise
return _this.$timeout(function() {
_this.counter += 1;
//Here we resolve the promise we created in the
// constructor only if the count is above 5
if (_this.counter > 5) {
_this.counterDef.resolve("Counter is above 5!");
}
return _this.counter;
});
},
countReached: function() {
//All defered objects have a 'promise' property
// that is an immutable version of the defered
// returning this means we can attach callbacks
// using the promise syntax to be executed (or not)
// at some point in the future.
return this.counterDef.promise;
}
};
app.service('promiseBasedCounter', PromiseBasedCounter);
function ClickCtrl(promiseBasedCounter) {
var _this = this;
_this.promiseBasedCounter = promiseBasedCounter;
_this.count = 0;
//Here we set up our callback. Notice this
// really has nothing to do with asyncronous I/O
// but we don't know when, or if, this code will be
// run in the future. However, it does provide an elegant
// way to handle some precondition without having to manually
// litter your code with the checks
_this.promiseBasedCounter.countReached()
.then(function(msg) {
_this.msg = msg;
});
}
ClickCtrl.$inject = ['promiseBasedCounter'];
ClickCtrl.prototype = {
incrementCounter: function() {
var _this = this;
//Whenever we increment, our service executes
// that code using $timeout and returns the promise.
// The promise is resolved with the current value of the counter.
_this.promiseBasedCounter.increment()
.then(function(count) {
_this.count = count;
});
}
};
app.controller('clickCtrl', ClickCtrl);
}());
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular.min.js"></script>
<div ng-app="promise-example" ng-controller="clickCtrl as ctrl">
<div class="container">
<h1>The current count is: <small>{{ctrl.count}}</small></h1>
<button type="button" class="btn btn-lg btn-primary" ng-click="ctrl.incrementCounter()">Click Me!</button>
</div>
<div class="container">
<h1>{{ctrl.msg}}</h1>
</div>
</div>
关于angularjs - 在 AngularJS 中使服务异步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30721646/