昨晚翻了一下,虽然都是一些旧知识,不过深刻下去对照着其余资料一块儿看,仍是能发现一些有意思的地方。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()
能够用在有大运算量的业务场景。
同步于个人博客