Angular $q 徹底指南

轉自:
xiaoyu2er:http://xiaoyu2er.github.io/20...git

若是想使用 $http 或者其餘異步操做, 那 $q 是必需要掌握的概念啦. Let’s get started!es6

如何理解$q, deferred object ?github

形象的講解angular中的$q與promise數組

假設有一個傢俱廠,而它有一個VIP客戶張先生。
有一天張先生須要一個豪華衣櫃,因而,他打電話給傢俱廠說我須要一個衣櫃,回頭作好了給我送來,這個操做就叫$q.defer,也就是延期,由於這個衣櫃不是如今要的,因此張先生這是在發起一個可延期的請求。
同時,傢俱廠給他留下了一個回執號,並對他說:咱們作好了會給您送過去,放心吧。這叫作promise,也就是承諾。
這樣,這個defer算是正式建立了,因而他把這件事記錄在本身的日記上,而且同時記錄了回執號,這叫作deferred,也就是已延期事件。
如今,張先生就不用再去想着這件事了,該作什麼作什麼,這就是「異步」的含義。
假設傢俱廠在一週後作完了這個衣櫃,並如約送到了張先生家(包郵哦,親),這就叫作deferred.resolve(衣櫃),也就是「已解決」。而這時候張先生只要簽收一下這個(衣櫃)參數就好了,固然,這個「郵包」中也不必定只有衣櫃,還能夠包含別的東西,好比廠家宣傳資料、產品名錄等。整個過程當中輕鬆愉快,誰也沒等誰,沒有浪費任什麼時候間。
假設傢俱廠在評估後發現這個規格的衣櫃咱們作不了,那麼它就須要deferred.reject(理由),也就是「拒絕」。拒絕沒有時間限制,能夠發生在給出承諾以後的任什麼時候候,甚至可能發生在快作完的時候。並且拒絕時候的參數也不只僅限於理由,還能夠包含一個道歉信,違約金之類的,總之,你想給他什麼就給他什麼,若是你以爲不會惹惱客戶,那麼不給也不要緊。
假設傢俱廠發現,本身正好有一個符合張先生要求的存貨,它就能夠用$q.when(現有衣櫃)來把這個承諾給張先生,這件事就當即被解決了,皆大歡喜,張先生可不在意你是從頭作的仍是現有的成品,只會驚歎於大家的效率之高。
假設這個傢俱廠對客戶格外的細心,它還可能經過deferred.notify(進展狀況)給張先生髮送進展狀況的「通知」。
這樣,整個異步流程就圓滿完成,不管成功或者失敗,張先生都沒有往裏面投入任何額外的時間成本。
好,咱們再擴展一下這個故事:
張先生此次須要作一個桌子,三把椅子,一張席夢思,可是他不但願今天收到個桌子,明天收到個椅子,後天又得簽收一次席夢思,而是但願傢俱廠作好了以後一次性送過來,可是他下單的時候又是分別下單的,那麼他就能夠從新跟傢俱廠要一個包含上述三個承諾的新承諾,這就是$q.all(桌子承諾,椅子承諾,席夢思承諾),
這樣,他就不用再關注之前的三個承諾了,直接等待這個新的承諾完成,到時候只要一次性簽收了前面的這些承諾就好了。promise

如何建立 promise -1異步

$q 支持兩種寫法, 第一種是相似於ES6標準構造函數寫法 $q(function resolver (resolve, reject) {})ide

注意:函數

+ ES6 寫法並不支持 progress/notify 的回調函數
+ 在構造函數中拋異常也並不會顯式的reject the promise

// var iWantResolve = false;
var iWantResolve = true;
function es6promise() {
    return $q(function (resolve, reject) {
        $timeout(function () {
            if (iWantResolve) {
                resolve("es6promise resolved");
            } else {
                reject("es6promise reject");
            }
        }, 1000)
    })
}

promise 的方法ui

promise.then(successCb, errCb, notifyCb)

其中successCb 將在 promise resolve 後被調用, errCb 將在 promise reject 後被調

notifyCb 將在 deferred.notify 後被調用, 能夠屢次調用

promise.catch == promise.then(null, errCb), 用於處理以前沒有被處理的 rejected promise

promise.finally 將最後被調用, 通常用於資源釋放的清理操做



es6promise()
    .then(function (data) {
        console.log(data);
    })
    .catch(function (err) {
        console.log(err);
    });
// if(iWantResolve == true) output: es6promise resolved
// if(iWantResolve = false) output: es6promise reject

如何建立 promise -2 code

第二種是相似於 commonJS 的寫法 $q.deferred()

function commonJsPromise() {
    var deferred = $q.defer();
    $timeout(function () {
        deferred.notify("commonJS notify");
        if (iWantResolve) {
            deferred.resolve("commonJS resolved");
        } else {
            deferred.reject("commonJS reject");
        }
    }, 500);
    return deferred.promise;
}
commonJsPromise()
    .then(function /** success callback**/(data) {
        console.log(data);
    }, function /** error callback **/ (err) {
        console.log(err);
    }, function /** progress callback **/ (update) {
        console.log(update);
    });
// if(iWantResolve == true) output: commonJS notify commonJS resolved
// if(iWantResolve = false) output: commonJS notify commonJS reject

$q.all

$q.all([promise1, promise1]) 接受一個包含若干個 promise 的數組,
等全部的 promise resolve 後, 其自己 resolve 包含上述結果的數組 [data1, data2]
若是上述 promise 有一個 reject, 那麼$q.all() 會把這個 rejected promise 做爲其 rejected promise (只有一個哦)
progress/notify 的 callback 並無用


$q.all([es6promise(), commonJsPromise()])
    .then(function (dataArr) {
        console.log("$q.all: ", dataArr);
    }, function (err) {
        console.log("$q.all: ", err)
    }, function /** unnecessary **/ (update) {
        console.log("$q.all", update);
    });
// if(iWantResolve == true) output: $q.all:  ["es6promise resolved", "commonJS resolved"]
// if(iWantResolve = false) output: $q.all:  es6promise reject

$q.reject, $q.when, $q.resolve

$q.reject() 當即返回一個rejected 的 promise, 在鏈式調用的時候頗有用
$q.resolve == $q.when(value, successCb, errorCb, progressCb)
value 多是一個 then-able 的 obj(便可以是 $q.defer() 返回的, 也能夠是其餘庫產生的), 也多是任意數據, 可是 $q.when 最終都會返回一個 promise
$q.when 既能夠寫成上述的構造函數形式, 也能夠寫成       $q.when(value).then(fn, fn, fn) 的形式


    $q.reject("instant reject")
    .catch(function (err) {
        console.log(err);
    });
// output: instant reject
$q.when(commonJsPromise(),
    function /** success callback **/(data) {
        console.log("$q.when success callback function: " + data);
        return "$q.when success callback return another value";
    })
    .then(function (data) {
        console.log("$q.when then function:" + data);
    });
// if(iWantResolve == true) output:
// $q.when success callback functionL: commonJS resolved
// $q.when then function:$q.when success callback return another value
// if(iWantResolve = false) output:
// $q.when err callback function: commonJS reject
// $q.when then function:undefined
$q.when("some value", function (data){
    console.log(data);
})
// output: some value

promise chains 鏈式調用

任何在 successCb, errCb 中返回的非 $q.reject()對象, 都將成爲一個 resolve 的 promise.
因此能夠出現以下語法
promise.then().then().then()

$q.when("1")
    .then(function (data) {
        console.log(data);
        return $q.reject(2);
    })
    .catch(function (err) {
        console.log(err);
        return 3;
    })
    .then(function (data) {
        console.log(data);
    })
// output: 1 2 3
相關文章
相關標籤/搜索