作為一個后端開發(fā)人員, 由于公司項目的需要. 最近開始轉(zhuǎn)向javascript.
由于我司一向秉承TDD(測試驅(qū)動開發(fā)) 和100% 覆蓋率的開發(fā)原則. 所以在做js 開發(fā)的時候, 免不了要對js 代碼進行單元測試.
普通的js 代碼還好, 但是遇到異步代碼( 如timers.setTimeout(callback)). 由于我司項目的特殊性, 并不能引入第三方的測試框架. 而只能使用原生的js 方法和特性來進行單元測試. 也就是我們的單元測試框架和assert 庫都是自己重寫的.
最后發(fā)現(xiàn)老馬的一篇文章 Testing Asynchronous JavaScript. 介紹了相關的方法.
總體的思路: mock 掉異步調(diào)用callback 的方法, 改為直接對callback 進行立即調(diào)用.
例如: 要對ajax 請求進行單元測試, 那么在測試文件中復寫 $.ajax.
$.ajax = function(ajaxOpts) {
var doneCallback = ajaxOpts.done;
doneCallback(simulatedAjaxResponse);
};
然后,這篇文章推薦使用Promise 來代替callback 來編寫異步方法. 作為一個后端人員, 又對Promise 進行了一番研究.
Promise
- 核心思想: 關注點從operation 的調(diào)用轉(zhuǎn)移到處理operation 的結果.
1, Promise
- 方法的調(diào)用返回promise, 而不是操作的結果.
- promise 是一種代理, 代表操作的future result.
- Promise 是對in process 的異步操作的封裝, 可以從方法返回, 傳遞給方法, 存儲在queue 中.
- jquery 中的deffer 就屬于promise, 這說明promise 解決的是一種帶有延遲的事件, 這個事件會被延遲到未來某個合適點再執(zhí)行.
- 執(zhí)行過程: 在promise 上注冊callback, 然后當操作完成且結果可用時, 由promise 執(zhí)行callback.
2, Promise 與異步
- 同步方法的特性: return value && throw exception.
- Promise 給予異步方法了同步的2個特性. 它規(guī)定方法必須返回一個Promise.
- Promise 對象有三種狀態(tài):
- Pending – Promise對象的初始狀態(tài),等到任務的完成或者被拒絕;
- Fulfilled – 任務執(zhí)行完成并且成功的狀態(tài);
- Rejected – 任務執(zhí)行完成并且失敗的狀態(tài)
- Promise 的可選行為:
- 被一個值填充.
- 拒絕并附帶exception.
- 這反映在then 方法接收的兩個回調(diào)函數(shù)上.
3, Then
- then 不是為了將callbacks 連接到一個聚合集合.
- 而是在一個Promise 上應用transformation, 并從該轉(zhuǎn)換中產(chǎn)生一個新的promise.
4, Immutable promise
- 方法必須返回一個新的promise. 這樣將一個promise 分配給多個消費者時,它們的狀態(tài)才不會互相干擾.
- 當promise 被fulfilled/failed 后,它就是immutable的.
- promise 的轉(zhuǎn)換, 會有4種情況(2*2, 具體參照第2節(jié)Promise 的可選行為).
- 而Jquery 的promise 只是簡單地將state mutate到寄存的promise 上.
- 當promise 被fulfilled/failed 后,它就是immutable的.
5, Exception
- 通過捕獲異常并將其轉(zhuǎn)換為rejection, 同時處理了
intentional(throw new Error("bad data"))/unintentional(aFunctionThatDoesNotExist())異常.- 異常會冒泡到最近的rejection handler.
6, Promise 規(guī)范
- Promise 是含有then 方法屬性的對象.
- 這樣就能在完全不知promise 的實現(xiàn)的情況下, 編寫庫代碼.