AngularJS中$q 服务的用法详解
一、$q的定位与设计目的
在 AngularJS 中,$q 是用于实现 Promise(承诺)机制的核心服务,主要用于:
- 管理和组织异步操作
- 避免回调地狱(callback hell)
- 与 AngularJS 的 Digest(脏检查)机制深度集成
- 为
$http、$timeout、$resource等服务提供统一的异步抽象
$q 的设计思想来源于 Promises/A+ 规范,但在早期 AngularJS 版本中并非完全等同于 ES6 Promise,而是针对 Angular 框架特性进行了扩展。
二、Promise 的核心概念
1. Promise 的三种状态
一个 Promise 对象在生命周期中只可能处于以下三种状态之一:
| 状态 | 含义 |
|---|---|
pending | 初始状态,未完成、未拒绝 |
fulfilled(resolved) | 操作成功完成 |
rejected | 操作失败 |
⚠️ 状态一旦从 pending 变为 fulfilled 或 rejected,就不可再改变。
2. Promise 的基本行为
- Promise 表示一个未来才会得到结果的值
- 可以通过
.then()、.catch()等方式注册回调 - 回调的执行顺序由
$q统一调度,并自动触发$digest
三、$q的核心 API
1.$q.defer()—— 延迟对象(Deferred)
(1)基本用法
var deferred = $q.defer();
deferred 对象包含两个关键部分:
| 属性 | 说明 |
|---|---|
deferred.promise | Promise 对象,对外暴露 |
deferred.resolve(value) | 标记成功 |
deferred.reject(reason) | 标记失败 |
deferred.notify(value) | 进度通知(较少使用) |
(2)示例
function asyncTask() {
var deferred = $q.defer();
setTimeout(function () {
if (Math.random() > 0.5) {
deferred.resolve('成功结果');
} else {
deferred.reject('失败原因');
}
}, 1000);
return deferred.promise;
}调用方:
asyncTask().then(
function (result) {
console.log(result);
},
function (error) {
console.error(error);
}
);2.promise.then()—— 注册成功与失败回调
(1)语法
promise.then(onFulfilled, onRejected, onNotified);
onFulfilled(value):成功回调onRejected(reason):失败回调onNotified(value):进度回调(可选)
(2)链式调用(非常重要)
promise
.then(function (data) {
return data + 1;
})
.then(function (data) {
return data * 2;
})
.then(function (finalResult) {
console.log(finalResult);
});关键原则:
then的返回值会被自动包装为一个新的 Promise
- 返回普通值 → 自动
resolve - 返回 Promise → 等待其完成
- 抛出异常 → 自动
reject
3.promise.catch()—— 失败处理
(1)语法
promise.catch(function (reason) {
// 错误处理
});
等价于:
promise.then(null, function (reason) {});
(2)推荐用法
asyncTask() .then(processData) .then(saveData) .catch(handleError);
👉 符合“错误集中处理”的工程实践
4.promise.finally()—— 结束处理
(1)用途
- 无论成功或失败都会执行
- 不接收 promise 的结果
- 不改变原 promise 的状态
(2)示例
asyncTask()
.then(successHandler)
.catch(errorHandler)
.finally(function () {
console.log('操作结束');
});
常用于:
- 关闭 loading
- 释放资源
- 记录日志
四、$q的静态方法
1.$q.resolve(value)/$q.when(value)
功能
将一个值或 Promise 转换为 $q Promise。
$q.when(10).then(function (value) {
console.log(value); // 10
});
常用于统一同步 / 异步接口返回值。
2.$q.reject(reason)
直接创建一个失败状态的 Promise。
return $q.reject('参数非法');
3.$q.all(promises)
(1)功能
并行执行多个 Promise,全部成功才成功。
(2)示例
$q.all({
user: getUser(),
order: getOrder()
}).then(function (results) {
console.log(results.user);
console.log(results.order);
});
- 任意一个 Promise 失败 → 整体失败
- 返回结果结构与输入一致
4.$q.race(promises)(较少使用)
- 返回最先完成的 Promise 的结果
- 成功或失败均可
五、$q与 AngularJS Digest 机制的关系
这是 $q 区别于原生 Promise 的核心优势。
1. 自动触发$digest
$q.when(data).then(function () {
$scope.value = 123;
});
- 不需要手动
$scope.$apply() - 视图会自动更新
2. 对比原生 Promise(早期版本)
Promise.resolve().then(function () {
$scope.value = 123;
// 视图可能不会更新
});
六、典型使用场景
1. 封装异步服务
app.service('UserService', function ($q, $http) {
this.getUser = function (id) {
var deferred = $q.defer();
$http.get('/user/' + id)
.then(function (res) {
deferred.resolve(res.data);
})
.catch(function (err) {
deferred.reject(err);
});
return deferred.promise;
};
});2. 串行异步流程控制
login() .then(loadProfile) .then(loadPermissions) .then(initApp) .catch(handleError);
七、最佳实践与注意事项
1.优先返回 Promise,而不是 Deferred
❌ 不推荐:
return deferred;
✅ 推荐:
return deferred.promise;
2. 避免“过度使用$q.defer()”
如果已有 Promise,直接返回即可:
return $http.get('/api');
3. 合理使用链式调用,避免嵌套
❌ 回调嵌套
✅ Promise 链
八、总结
$q 是 AngularJS 异步编程的核心机制,其主要特点包括:
- 基于 Promise/A+ 思想
- 与 Digest 机制深度集成
- 支持链式调用、错误传播与并发控制
- 是构建高可维护 AngularJS 应用的基础设施
到此这篇关于AngularJS中$q 服务的用法的文章就介绍到这了,更多相关AngularJS $q 服务内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
在JavaScript的AngularJS库中进行单元测试的方法
这篇文章主要介绍了在JavaScript的AngularJS库中进行单元测试的方法,主要针对AngularJS中的控制器相关,需要的朋友可以参考下2015-06-06
Angular4项目中添加i18n国际化插件ngx-translate的步骤详解
这篇文章主要跟大家介绍了关于Angular4项目中添加i18n国际化插件ngx-translate的步骤,文中介绍的非常详细,对大家具有一定的参考学习价值,需要的朋友们下面来一起看看吧。2017-07-07


最新评论