摘要:謝謝大大指出的關(guān)于中用的不到位的錯誤,貼上大大推薦的文章中的菜鳥和高階錯誤,文章很詳細(xì)說明了一些使用中的錯誤和指導(dǎo)。另外更正內(nèi)容在后面補(bǔ)充。從開始說到異步流程控制,之前用的比較多的是的。
謝謝n?i?g?h?t?i?r?e?大大指出的關(guān)于Promise中catch用的不到位的錯誤,貼上大大推薦的文章Promise中的菜鳥和高階錯誤,文章很詳細(xì)說明了一些Promise使用中的錯誤和指導(dǎo)。另外更正內(nèi)容在后面補(bǔ)充。
從 jQuery $.Deferred() 開始說到異步流程控制,之前用的比較多的是jQ的Deferred。那Deferred是個啥呢,不清楚沒關(guān)系,直接控制臺來打印看下:
喔!看得出$.Deferred()后是個對象,其下面有著熟悉的done, fail, always字眼(對,,是不是有點(diǎn)熟悉了呢?沒錯!如果經(jīng)常用ajax的話就會經(jīng)常接觸到這些貨色)。 當(dāng)然了,不止這些,還有最最最重要的reject和resolve方法,說到這兩個方法,就得引出下Deferred的狀態(tài)機(jī)制了——其實很簡單,實例化后用上圖中的state方法就可以查看($.Deferred().state()),有三種狀態(tài)
執(zhí)行resolve/reject前,返回值是pending
執(zhí)行了resolve,返回值是resolved
執(zhí)行了reject,返回值是rejected
直接來試著用下吧!這里我們假設(shè)執(zhí)行一個隨機(jī)延時的setTimeout的異步操作,在setTimeout異步操作結(jié)束后,根據(jù)延時大小,做出不同回應(yīng) ! 代碼:
function log (msg) { console.log(msg); } // 包裝一個異步操作 var Async = function () { // 生成一個0到5秒的延遲 var delay = Math.floor(Math.random() * 5); // 創(chuàng)建一個Deffered對象 var dfd = $.Deferred(); // 這里調(diào)用一個異步操作 setTimeout(function(){ if (delay <= 2) { // 置dfd狀態(tài)為resolved dfd.resolve("一切正常!"); } else { // 置dfd狀態(tài)為rejected dfd.reject("超時了!"); } }, delay * 1000) // 這里要返回Deferred下的promise對象Dererred對象的原因下面會解釋 return dfd.promise(); } Async() .done(function (data) { log(data) // 如果延遲不大于三秒 輸出dfd.resolve()中的數(shù)據(jù) "一切正常!" }) .fail(function (err) { log(err) // 反之則 輸出dfd.reject()中的數(shù)據(jù) "超時了!" }) .always(function () { log("執(zhí)行完畢!"); // 總是輸出 "執(zhí)行完畢!" })嘗試下通俗理解整個流程就是
講個比較爛的比喻啊在某個操作開始前創(chuàng)建一個Deferred對象,然后執(zhí)行操作
操作間可根據(jù)情況給dfd執(zhí)行relove或者reject方法改變狀態(tài)并傳入數(shù)據(jù)
最后返回出dfd的對象下的一個promise對象,這里不直接返回dfd對象是因為dfd對象的狀態(tài)是在第一次resolve或者reject后還可以更改的(不過里面的數(shù)據(jù)以第一次為準(zhǔn))!!
操作執(zhí)行后用done和fail方法分別接受resolve和reject狀態(tài)和數(shù)據(jù)(一一對應(yīng))然后執(zhí)行回調(diào)(其實1.8還有個then方法,接受兩個參數(shù),第一個參數(shù)為resolve的回調(diào),第二個為reject的)
always是無論resolve還是reject都會執(zhí)行。
我是一個流水線車間質(zhì)檢工人,就在平常的這樣的一天,來了一批玩具熊,嗯,接下來應(yīng)該是這樣的
這里再上一張圖來解釋下!來了一個檢查目標(biāo)($.Dererred()),這時你還不知道它是好是壞
我靠我?guī)资甑男聳|方炒菜技巧檢驗產(chǎn)品并給良品貼上了合格標(biāo)簽(dfd.res* olve(合格標(biāo)簽)),次品貼上回廠標(biāo)簽* (dfd.reject(回廠標(biāo)簽及原因))
然后通過的良品和次品都來到了各自的包裝口打好包,不能對里面的標(biāo)簽做更改了!(dfd.promise())去往自己下一個目的地(return dfd.promise)
再然后良品來到了熊孩子手中(.done()),次品回到了廠里(.fail()),最后不管玩具熊到了哪里,其實都會被開膛破肚(.always()好吧這里有點(diǎn)牽強(qiáng))
還有值得說一下的是always里的回調(diào),我在實際中使用時發(fā)現(xiàn)總是在done和fail里的回調(diào)(假設(shè)為同步)執(zhí)行完畢后后執(zhí)行的。
金掌銀掌仙人掌 掌聲有請 ES6 Promise和上面一樣,先打印一下!
可以看到Promise下也有熟悉的resolve和reject方法,好像和jQ的Deferred頗為相似!但是不是少了點(diǎn)什么呢?done或者fail之類的流程控制的方法呢??
不急,其實展開prototype原型上就可以看到掛載著的then方法了!(像極了jQ1.8后那個then,不過我覺得應(yīng)該說是jQ來遵循Promise才對)
Promise其實就是個構(gòu)造函數(shù),還是之前的例子,這里我們分三步走
var Async = function () { // 第一步,新建個promise對象,所需的異步操作在其中進(jìn)行 var prms = new Promise(function(resolve, reject){ // 生成一個0到5秒的延遲 var delay = Math.floor(Math.random() * 5); // 這里調(diào)用一個異步操作 setTimeout(function(){ // 第二步, 根據(jù)情況置promise為resolve或者reject if (delay <= 2) { // 置dfd狀態(tài)為resolved resolve("一切正常!"); } else { // 置dfd狀態(tài)為rejected reject("超時了!"); } }, delay * 1000) }) // 第三步,返回這個Promise對象 return prms } // 強(qiáng)大的來了 Async() // then接受兩個函數(shù)分別處理resolve和reject兩種狀態(tài) .then( function(data) { console.log(data) // 一切正常! }, function(err) { console.log(err) // 超時了!! })
粗粗一看好像和Dererred不能更像了,,不過細(xì)心點(diǎn)的話可以發(fā)現(xiàn)我們在函數(shù)里直接返回了prms這個對象,而不是像之前把包裝了一層。。。對!因為Promise的特性就是一旦第一次賦予了狀態(tài)后面就無法更改了,這也算省心多了吧。但是問題來了,我為什么要選擇用Promise呢??
這么說吧,它是原生的 它是原生的 它是原生的!,還有可以鏈?zhǔn)芥準(zhǔn)芥準(zhǔn)芥準(zhǔn)秸{(diào)用!,我們可以把每一個then或者catch當(dāng)做一個處理器, 比如這樣
Async() // 這里暫時只處理resolve .then(function(data) { console.log(data) // 一切正常! return Promise.resolve("隨便什么"); }) // 下一個then處理器接收到上一個處理器發(fā)出的數(shù)據(jù) .then(function(data2) { console.log(data2) // 隨便什么 return Promise.reject("錯誤數(shù)據(jù)"); }) ...
對!沒看錯,其實在then里面你還可以return其他的promise對象傳并遞數(shù)據(jù)!更有甚你甚至可以什么都不返回,比如說這樣
Async() .then(function(data) { console.log(data) // 一切正常! }) // 上面那個處理器如果不return任何東西 就會默認(rèn)返回個resolve(undefined) // 然后下面的處理器就會接收到這個resolve(undefined) .then(function(data2) { console.log(data2) // undefined // 雖然沒有數(shù)據(jù)來處理,但是你還可以在這里做一些事情啊,例如 return Promise.reject("錯誤數(shù)據(jù)"); }) // 嗒噠,catch就這么登場了,這里用catch處理上個then處理器發(fā)出的reject .catch(fucntion(err){ console.log(err) // 錯誤數(shù)據(jù) return "那直接返回個字符串呢?" }) // 上個catch處理器返回了個字符串其實也會被下個處理器接受 // 相當(dāng)于resolve("那直接返回個字符串呢?") .then(function(data3){ console.log(data3) // 那直接返回個字符串呢? }) // 好,接著我們來試試在沒有返回任何東西的情況下接一個catch處理器 .catch(function(err2){ console.log(err2) // 我們可以來猜一下上面會輸出什么,undefined嗎? // 錯,其實這里什么都不會輸出,因為這個catch接收的是resolve // 但它并不會吞沒這個resolve而是選擇跳過,例如我們這里再返回 return Promise.resolve("這個字符串會被跳過") }) // 這里緊接著個then處理器,它接受到的數(shù)據(jù)呢 // 其實并不是上個catch返回的resolve("這個字符串會被跳過") // 而是catch之前那個then處理器默認(rèn)返回的resolve(undefined) .then(function(data4){ console.log(data4) // undefined })
有點(diǎn)被繞暈了吧
我們用一句話來梳理下:鏈?zhǔn)秸{(diào)下會有一串then和catch,這些then和catch處理器會按照順序接受上個處理器所產(chǎn)生的返回值,并且根據(jù)傳入的狀態(tài)做出不同響應(yīng),要么跳過,要么處理(所以上面23行處的catch處理器被跳過了)
ps: 上面我們用的then處理器只有一個函數(shù)參數(shù),所以只會處理resolve狀態(tài),如果是兩個then就可以處理reject了。
----更新于5月11日-----
catch使用的注意上面一塊代碼中引出了catch處理器, 之前以為 cacth() 是 then(null, ...) 的語法糖, 其實這么說不完全正確(功能層面上來說這兩個是完全相同的沒錯——都是處理reject和異常),但是到了實際使用中Promise中的菜鳥和高階錯誤文章中給出了明確的情況證明,這里貼一下:
首先只處理異常情況,下面兩個是等價的
somePromise().catch(function (err) { // 處理異常 }); somePromise().then(null, function (err) { // 處理異常 });
但是,如果不只是處理異常的下面兩種情況下就不一樣了
somePromise().then(function () { return otherPromise(); }).catch(function (err) { // 處理異常 }); somePromise().then(function () { return otherPromise(); }, function (err) { // 處理異常 });
不夠清楚嗎?那么如果是這樣呢?如果第一個回調(diào)函數(shù)拋出一個錯誤會發(fā)生什么?
somePromise().then(function () { throw new Error("這里錯了!"); }).catch(function (err) { console.log(err) // 這里錯了! :) }); somePromise().then( function () { throw new Error("這里錯了"); }, function (err) { console.log(err) // 未知 :( // 并沒有catch到上面那個Error });
結(jié)論就是,當(dāng)使用 then(resolveHandler, rejectHandler) , rejectHandler 不會捕獲在 resolveHandler 中拋出的錯誤!
貼完了,好吧,這有什么用呢?看似這個注意項并不影響平常使用,原文作者也說道:
因為,筆者的個人習(xí)慣是從不使用then方法的第二個參數(shù),轉(zhuǎn)而使用 catch() 方法
那么,問題來了,如何正確的使用catch呢? 其實我沒有很好的想明白,希望指教,隨便拋兩個磚
// 1 somePromise() .then(resolveHandler) // 這個catch會處理somePromise或者resolveHandler的異常 .catch(rejectHandler) .then(otherResolveHandler) // 而這個catch呢只會處理resolveHandler的異常 .catch(otherRejectHandler) // 2 somePromise() .then(resolveHandler) .then(otherResolveHandler) // 至于這個catch則會處理somePromise、resolveHandler和otherResolveHandler的異常 .catch(rejectHandler) // 3 somePromise() .catch(console.log.bind(console)) //等價于 .catch(function(err){ console.log(err) })
哈哈哈哈哈哈,還是好好再去想想Promise去了,弄明白了再來補(bǔ)充,再次謝謝@n?i?g?h?t?i?r?e?大大,荊柯刺秦王
寫的很粗糙,有錯誤的地方希望多多指教!!
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/79401.html
摘要:而事件循環(huán)是主線程中執(zhí)行棧里的代碼執(zhí)行完畢之后,才開始執(zhí)行的。由此產(chǎn)生的異步事件執(zhí)行會作為任務(wù)隊列掛在當(dāng)前循環(huán)的末尾執(zhí)行。在下,觀察者基于監(jiān)聽事件的完成情況在下基于多線程創(chuàng)建。 主要問題: 1、JS引擎是單線程,如何完成事件循環(huán)的? 2、定時器函數(shù)為什么計時不準(zhǔn)確? 3、回調(diào)與異步,有什么聯(lián)系和不同? 4、ES6的事件循環(huán)有什么變化?Node中呢? 5、異步控制有什么難點(diǎn)?有什么解決方...
摘要:我們都知道提供了異步寫法,但是大部分的公司都是寫的,那我們?nèi)绾斡脕韺懞彤惒揭粯拥膶懛剡@個知道的人不多下面我們就來寫寫把注意以上關(guān)鍵執(zhí)行完成已經(jīng)封裝好的員工定義執(zhí)行完成成功失敗返回最終返回使用員工對象這樣就可以使用了,其實的前身就是的,封 我們都知道es6提供了promise異步寫法,但是大部分的公司都是jq寫的,那我們?nèi)绾斡肑q來寫和promise異步一樣的寫法呢?這個知道的人不多下...
摘要:三模式模式其實包含兩部分和。六化在編碼的時候,想要用進(jìn)行異步操作流程控制,就要將當(dāng)前的異步回調(diào)函數(shù)封裝成。 一、什么是promise/deferred 模式 promise/deferred 模式是,根據(jù)promise/A 或者它的增強(qiáng)修改版promise/A+ 規(guī)范 實現(xiàn)的promise異步操作的一種實現(xiàn)方式。 異步的廣度使用使得回調(diào),嵌套出現(xiàn),但是一但出現(xiàn)深度的嵌套,就會讓codi...
摘要:單線程就意味著,所有任務(wù)需要排隊,前一個任務(wù)結(jié)束,才會執(zhí)行后一個任務(wù)。這決定了它只能是單線程,否則會帶來很復(fù)雜的同步問題。小結(jié)本身是單線程的,并沒有異步的特性。當(dāng)異步函數(shù)執(zhí)行時,回調(diào)函數(shù)會被壓入這個隊列。 走在前端的大道上 本篇將自己讀過的相關(guān) js異步 的文章中,對自己有啟發(fā)的章節(jié)片段總結(jié)在這(會對原文進(jìn)行刪改),會不斷豐富提煉總結(jié)更新。 概念 JS 是單線程的語言。 單線程就意味著...
摘要:假設(shè)家具廠在一周后做完了這個衣柜,并如約送到了張先生家包郵哦,親,這就叫做衣柜,也就是已解決。這樣,整個異步流程就圓滿完成,無論成功或者失敗,張先生都沒有往里面投入任何額外的時間成本。 如果想使用 $http 或者其他異步操作, 那 $q 是必須要掌握的概念啦. Lets get started! 如何理解$q, deferred object ? 形象的講解angular中的$q與p...
閱讀 2125·2021-11-19 09:58
閱讀 1713·2021-11-15 11:36
閱讀 2877·2019-08-30 15:54
閱讀 3396·2019-08-29 15:07
閱讀 2767·2019-08-26 11:47
閱讀 2818·2019-08-26 10:11
閱讀 2508·2019-08-23 18:22
閱讀 2754·2019-08-23 17:58