使用一段 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, 觸發機制

留言
張貼留言