昨晚翻了一下,雖然都是一些舊知識,不過深刻下去對照着其餘資料一塊兒看,仍是能發現一些有意思的地方。javascript
反正以前我是沒搞懂函數式和命令式的區別,也很疑惑函數式編程中,若是出現分支怎麼辦,昨晚總算弄明白了。html
// 咱們有4個基礎函數,會根據不一樣的業務邏輯進行組裝使用 // 自動建立 function autoCreate () {} // 自動同步 function autoSync () {} // 流程 A function processA () {} // 流程 B function processB () {} // 流程 A 與流程 B 在業務上是互斥的
傳統的命令式編程,咱們會這樣寫業務邏輯java
function service (errorHandler) { var result; if (!id) { result = autoCreate(); if (result.error) { errorHandler(result); } } if (type === 'a') { processA(); if (result.error) { errorHandler(result); } } if (type === 'b') { result = processB(); if (result.error) { errorHandler(result); } } if (!isSync) { result = autoSync(); if (result.error) { errorHandler(result); } } }
而函數式編程,咱們則能夠這樣寫業務邏輯。ajax
// service 自己不是一個異步業務,因此直接使用 Promise.resolve() var service = Promise.resolve(); // 須要對autoCreate()等四個基礎函數作 Promise 改造 service.then(autoCreate) .then(processA) .then(processB) .then(autoSync) .catch(errorHandler);
這裏可能會有一個疑惑,互斥的 processA 和 processB 怎麼進入了同一個處理流程,這樣和需求就不符合了?編程
在這種狀況下,咱們還須要在 processA 和 processB 的內部,把退出條件補上。瀏覽器
function processA () { return new Promise(function(resolve, reject){ if (type !== 'A') { resolve(); } // 這裏繼續 processA 的邏輯代碼 }); }
JS 在執行的時候,有一個函數調用棧,棧裏面放着一個個的函數調用幀,這些幀保存着所屬函數所需的全部變量信息。異步
函數調用會在內存造成一個「調用記錄」,又稱「調用幀」(call
frame),保存調用位置和內部變量等信息。若是在函數A的內部調用函數B,那麼在A的調用幀上方,還會造成一個B的調用幀。等到B運行結束,將結果返回到A,B的調用幀纔會消失。若是函數B內部還調用函數C,那就還有一個C的調用幀,以此類推。全部的調用幀,就造成一個「調用棧」(call
stack)。函數式編程
咱們發現有時候執行 window.open()
,能正常打開新窗口或者新的標籤頁,而有時卻又不行,會被瀏覽器攔截。函數
其緣由是瀏覽器會根據當前調用棧,找到最初的caller,若是不是用戶觸發的,則攔截。優化
因爲函數調用的時候會生成新的調用幀,當遞歸調用的時候,調用棧中的調用幀增加會很是厲害,最終致使內存耗盡而觸發 RangeError。
若是把函數調用放在函數塊的最後一條語句,且不在使用外層函數的變量了,則外層函數所佔用的調用幀已無存在乎義。在進入內層函數的時候,能夠直接用內層函數的調用幀替換掉外層函數的調用幀,從而大大減小內存佔用。
Partial Application 的模式,用來作 Library 和 SDK 都挺好的。一個可定製性高的底層接口,再經過相似 _.partial()
的方式,提供一個開箱即用的上層接口。就像 $.ajax()
和 $.get()
同樣。
_.defer()
和 _.memoize()
能夠用在有大運算量的業務場景。
同步於個人博客