使用一段 jQuery 時間至今,終於到了感嘆技術歲月的無情時刻(感謝 jQuery 過去那段輝煌),現在已一堆資料驅動的框架出現,幫助我們更容易開發複雜的前後端系統,慢慢也因為效能問題,最近開始要淘汰 jQuery 語法。
參考下面兩篇文章之後︰
原生js替換jQuery各種方法-中文版
https://segmentfault.com/a/1190000016594035
jQuery Promise 與 bluebird Promise 對應說明
https://github.com/petkaantonov/bluebird/blob/master/docs/docs/coming-from-other-libraries.md
決定先把使用 jQuery Promise 的部份先替換掉,我這邊改用 bluebird。不過,就再替換之後發現有一些重大問題,例如把 jQuery 的 done, fail 改為 bluebird 的 then, catch 時,竟然再某些情況下的觸發機制不同,這實在讓我找了許久才發現不同處。
主要為 bluebird 為實做 Promises/A+ 規範,其 catch 會把錯誤狀態視為已處理,之後可繼續使用 then 監聽後續事件消息。而 jQuery 的 fail 後不同,Promise 狀態依然是 reject,故再之後所接續監聽鏈式消息都是只有 fail,而若我們依照 jQuery 所設計開發的程序,採用硬轉語法 done, fail 成為 bluebird 的 then, catch 時,就會遇到這問題。
以下為單html檔測試範例︰
載入後畫面為︰
由 console.log 可看到 jqtest_L2 與 bbtest_L2 都是能接收到錯誤狀態(fail, catch),但 jqtest_L3 與 bbtest_L3 確觸發到不同事件,jQuery依然是觸發到 fail,但 bluebird 反而是觸發 then 事件。
若要避免上述此問題,記得改為 bluebird 後,函數各層(以本例來說是L2, L3層)使用或回傳 bluebird Promise 時,要接收 catch 消息就再另外包一層後,在裡面呼叫 reject 才回傳 Promise,其非同步訊息處理流程就會等同於 jQuery 版的運行方式。
#Javascript, jQuery, Deferred, bluebird, Promise, done, fail, then, catch, 觸發機制
參考下面兩篇文章之後︰
原生js替換jQuery各種方法-中文版
https://segmentfault.com/a/1190000016594035
jQuery Promise 與 bluebird Promise 對應說明
https://github.com/petkaantonov/bluebird/blob/master/docs/docs/coming-from-other-libraries.md
決定先把使用 jQuery Promise 的部份先替換掉,我這邊改用 bluebird。不過,就再替換之後發現有一些重大問題,例如把 jQuery 的 done, fail 改為 bluebird 的 then, catch 時,竟然再某些情況下的觸發機制不同,這實在讓我找了許久才發現不同處。
主要為 bluebird 為實做 Promises/A+ 規範,其 catch 會把錯誤狀態視為已處理,之後可繼續使用 then 監聽後續事件消息。而 jQuery 的 fail 後不同,Promise 狀態依然是 reject,故再之後所接續監聽鏈式消息都是只有 fail,而若我們依照 jQuery 所設計開發的程序,採用硬轉語法 done, fail 成為 bluebird 的 then, catch 時,就會遇到這問題。
以下為單html檔測試範例︰
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8" /> <title>jQuery與bluebird Promise Demo</title> <!--使用jquery--> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <!--使用bluebird--> <script src="https://cdnjs.cloudflare.com/ajax/libs/bluebird/3.5.2/bluebird.min.js"></script> <script type="text/javascript"> let B = Promise.noConflict(); //重新命名 B.onPossiblyUnhandledRejection(function (e, promise) { }); //對promise全部預處理Unhandled Rejection, 避免沒catch跳出警告 </script> <!--使用lodash--> <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script> <script> function genDF_jq() { //回傳jQuery Deferred, 預設能鏈式處理 return $.Deferred(); } function genDF_bb() { //回傳bluebird Promise, 使能支援鏈式處理 let resolve, reject; let promise = new B(function () { resolve = arguments[0]; reject = arguments[1]; }); promise.resolve = resolve; promise.reject = reject; return promise; } function jqtest_L1() { //jQuery測試第1層呼叫 let df = genDF_jq(); //延遲1秒就reject _.delay(function () { let msg = 'jqtest_L1 reject'; console.log(msg); df.reject(msg); }, 1000); return df; } function jqtest_L2() { //jQuery測試第2層呼叫 //回傳L1並先監聽done與fail事件 return jqtest_L1() .done(function () { console.log('jqtest_L2 done'); }) .fail(function () { console.log('jqtest_L2 fail'); }); } function jqtest_L3() { //jQuery測試第3層呼叫 //回傳L2並先監聽done與fail事件 return jqtest_L2() .done(function () { console.log('jqtest_L3 done'); }) .fail(function () { console.log('jqtest_L3 fail'); }); } function bbtest_L1() { //bluebird測試第1層呼叫 let df = genDF_bb(); //延遲1秒就reject _.delay(function () { let msg = 'bbtest_L1 reject'; console.log(msg); df.reject(msg); }, 1000); return df; } function bbtest_L2() { //bluebird測試第2層呼叫 //回傳L1並先監聽then與catch事件 return bbtest_L1() .then(function () { console.log('bbtest_L2 then'); }) .catch(function () { console.log('bbtest_L2 catch'); }); } function bbtest_L3() { //bluebird測試第3層呼叫 //回傳L2並先監聽then與catch事件 return bbtest_L2() .then(function () { console.log('bbtest_L3 then'); }) .catch(function () { console.log('bbtest_L3 catch'); }); } $(function () { jqtest_L3(); bbtest_L3(); }); </script> </head> <body> </body> </html>
載入後畫面為︰
由 console.log 可看到 jqtest_L2 與 bbtest_L2 都是能接收到錯誤狀態(fail, catch),但 jqtest_L3 與 bbtest_L3 確觸發到不同事件,jQuery依然是觸發到 fail,但 bluebird 反而是觸發 then 事件。
若要避免上述此問題,記得改為 bluebird 後,函數各層(以本例來說是L2, L3層)使用或回傳 bluebird Promise 時,要接收 catch 消息就再另外包一層後,在裡面呼叫 reject 才回傳 Promise,其非同步訊息處理流程就會等同於 jQuery 版的運行方式。
#Javascript, jQuery, Deferred, bluebird, Promise, done, fail, then, catch, 觸發機制
留言
張貼留言