AngularJS中$q 服務(wù)的用法詳解
一、$q的定位與設(shè)計(jì)目的
在 AngularJS 中,$q 是用于實(shí)現(xiàn) Promise(承諾)機(jī)制的核心服務(wù),主要用于:
- 管理和組織異步操作
- 避免回調(diào)地獄(callback hell)
- 與 AngularJS 的 Digest(臟檢查)機(jī)制深度集成
- 為
$http、$timeout、$resource等服務(wù)提供統(tǒng)一的異步抽象
$q 的設(shè)計(jì)思想來(lái)源于 Promises/A+ 規(guī)范,但在早期 AngularJS 版本中并非完全等同于 ES6 Promise,而是針對(duì) Angular 框架特性進(jìn)行了擴(kuò)展。
二、Promise 的核心概念
1. Promise 的三種狀態(tài)
一個(gè) Promise 對(duì)象在生命周期中只可能處于以下三種狀態(tài)之一:
| 狀態(tài) | 含義 |
|---|---|
pending | 初始狀態(tài),未完成、未拒絕 |
fulfilled(resolved) | 操作成功完成 |
rejected | 操作失敗 |
?? 狀態(tài)一旦從 pending 變?yōu)?fulfilled 或 rejected,就不可再改變。
2. Promise 的基本行為
- Promise 表示一個(gè)未來(lái)才會(huì)得到結(jié)果的值
- 可以通過(guò)
.then()、.catch()等方式注冊(cè)回調(diào) - 回調(diào)的執(zhí)行順序由
$q統(tǒng)一調(diào)度,并自動(dòng)觸發(fā)$digest
三、$q的核心 API
1.$q.defer()—— 延遲對(duì)象(Deferred)
(1)基本用法
var deferred = $q.defer();
deferred 對(duì)象包含兩個(gè)關(guān)鍵部分:
| 屬性 | 說(shuō)明 |
|---|---|
deferred.promise | Promise 對(duì)象,對(duì)外暴露 |
deferred.resolve(value) | 標(biāo)記成功 |
deferred.reject(reason) | 標(biāo)記失敗 |
deferred.notify(value) | 進(jìn)度通知(較少使用) |
(2)示例
function asyncTask() {
var deferred = $q.defer();
setTimeout(function () {
if (Math.random() > 0.5) {
deferred.resolve('成功結(jié)果');
} else {
deferred.reject('失敗原因');
}
}, 1000);
return deferred.promise;
}調(diào)用方:
asyncTask().then(
function (result) {
console.log(result);
},
function (error) {
console.error(error);
}
);2.promise.then()—— 注冊(cè)成功與失敗回調(diào)
(1)語(yǔ)法
promise.then(onFulfilled, onRejected, onNotified);
onFulfilled(value):成功回調(diào)onRejected(reason):失敗回調(diào)onNotified(value):進(jìn)度回調(diào)(可選)
(2)鏈?zhǔn)秸{(diào)用(非常重要)
promise
.then(function (data) {
return data + 1;
})
.then(function (data) {
return data * 2;
})
.then(function (finalResult) {
console.log(finalResult);
});關(guān)鍵原則:
then的返回值會(huì)被自動(dòng)包裝為一個(gè)新的 Promise
- 返回普通值 → 自動(dòng)
resolve - 返回 Promise → 等待其完成
- 拋出異常 → 自動(dòng)
reject
3.promise.catch()—— 失敗處理
(1)語(yǔ)法
promise.catch(function (reason) {
// 錯(cuò)誤處理
});
等價(jià)于:
promise.then(null, function (reason) {});
(2)推薦用法
asyncTask() .then(processData) .then(saveData) .catch(handleError);
?? 符合“錯(cuò)誤集中處理”的工程實(shí)踐
4.promise.finally()—— 結(jié)束處理
(1)用途
- 無(wú)論成功或失敗都會(huì)執(zhí)行
- 不接收 promise 的結(jié)果
- 不改變?cè)?promise 的狀態(tài)
(2)示例
asyncTask()
.then(successHandler)
.catch(errorHandler)
.finally(function () {
console.log('操作結(jié)束');
});
常用于:
- 關(guān)閉 loading
- 釋放資源
- 記錄日志
四、$q的靜態(tài)方法
1.$q.resolve(value)/$q.when(value)
功能
將一個(gè)值或 Promise 轉(zhuǎn)換為 $q Promise。
$q.when(10).then(function (value) {
console.log(value); // 10
});
常用于統(tǒng)一同步 / 異步接口返回值。
2.$q.reject(reason)
直接創(chuàng)建一個(gè)失敗狀態(tài)的 Promise。
return $q.reject('參數(shù)非法');
3.$q.all(promises)
(1)功能
并行執(zhí)行多個(gè) Promise,全部成功才成功。
(2)示例
$q.all({
user: getUser(),
order: getOrder()
}).then(function (results) {
console.log(results.user);
console.log(results.order);
});
- 任意一個(gè) Promise 失敗 → 整體失敗
- 返回結(jié)果結(jié)構(gòu)與輸入一致
4.$q.race(promises)(較少使用)
- 返回最先完成的 Promise 的結(jié)果
- 成功或失敗均可
五、$q與 AngularJS Digest 機(jī)制的關(guān)系
這是 $q 區(qū)別于原生 Promise 的核心優(yōu)勢(shì)。
1. 自動(dòng)觸發(fā)$digest
$q.when(data).then(function () {
$scope.value = 123;
});
- 不需要手動(dòng)
$scope.$apply() - 視圖會(huì)自動(dòng)更新
2. 對(duì)比原生 Promise(早期版本)
Promise.resolve().then(function () {
$scope.value = 123;
// 視圖可能不會(huì)更新
});
六、典型使用場(chǎng)景
1. 封裝異步服務(wù)
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);
七、最佳實(shí)踐與注意事項(xiàng)
1.優(yōu)先返回 Promise,而不是 Deferred
? 不推薦:
return deferred;
? 推薦:
return deferred.promise;
2. 避免“過(guò)度使用$q.defer()”
如果已有 Promise,直接返回即可:
return $http.get('/api');
3. 合理使用鏈?zhǔn)秸{(diào)用,避免嵌套
? 回調(diào)嵌套
? Promise 鏈
八、總結(jié)
$q 是 AngularJS 異步編程的核心機(jī)制,其主要特點(diǎn)包括:
- 基于 Promise/A+ 思想
- 與 Digest 機(jī)制深度集成
- 支持鏈?zhǔn)秸{(diào)用、錯(cuò)誤傳播與并發(fā)控制
- 是構(gòu)建高可維護(hù) AngularJS 應(yīng)用的基礎(chǔ)設(shè)施
到此這篇關(guān)于AngularJS中$q 服務(wù)的用法的文章就介紹到這了,更多相關(guān)AngularJS $q 服務(wù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解在Angular項(xiàng)目中添加插件ng-bootstrap
這篇文章主要介紹了詳解在 Angular 項(xiàng)目中添加插件 ng-bootstrap,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-07
AngularJS監(jiān)聽(tīng)路由變化的方法
本篇文章主要介紹了AngularJS監(jiān)聽(tīng)路由變化的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-03-03
AngularJS開(kāi)發(fā)教程之控制器之間的通信方法分析
這篇文章主要介紹了AngularJS開(kāi)發(fā)教程之控制器之間的通信方法,結(jié)合實(shí)例形式較為詳細(xì)的分析了AngularJS控制器之間通信的三種常用方式及相關(guān)使用技巧,需要的朋友可以參考下2016-12-12
AngularJS使用ng-inlude指令加載頁(yè)面失敗的原因與解決方法
這篇文章主要介紹了AngularJS使用ng-inlude指令加載頁(yè)面失敗的原因與解決方法,對(duì)比不同瀏覽器錯(cuò)誤提示分析了加載失敗的原因及通過(guò)http訪問(wèn)的解決方法,需要的朋友可以參考下2017-01-01
用WebStorm進(jìn)行Angularjs 2開(kāi)發(fā)(環(huán)境篇:Windows 10,Angular-cli方式)
這篇文章主要介紹了用WebStorm進(jìn)行Angularjs 2開(kāi)發(fā)(環(huán)境篇:Windows 10,Angular-cli方式),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-12-12
詳解webpack+angular2開(kāi)發(fā)環(huán)境搭建
這篇文章主要介紹了詳解webpack+angular2開(kāi)發(fā)環(huán)境搭建,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06
AngularJS中過(guò)濾器的使用與自定義實(shí)例代碼
這篇文章運(yùn)用實(shí)例代碼給大家介紹了angularjs中過(guò)濾器的使用和自定義過(guò)濾器,對(duì)大家學(xué)習(xí)AngularJS具有一定的參考借鑒價(jià)值,感興趣的朋友們可以參考借鑒。2016-09-09

