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