Node是首个将异步大规模带到应用层面的平台,它从内存运行机制到API设计,都大量使用异步,它的优势在于高性能,但缺点在于异步编程的流程控制其实是有悖于自然语言的线性思维习惯的。
开始Node的js异步编程前,需要了解js函数式编程,因为它是异步编程的基础。
js中函数是一等公民,使用起来非常自由,可以被调用、被作为参数、被作为返回值。
普通函数可以接收基本的数据类型或对象引用作为参数,返回的也是基本数据类型或对象引用:
function foo( x ){
return x;
}
高阶函数则是一种可以把函数作为参数,也可以把函数作为返回值的函数:
function foo( x ){
return fn(){
return x;
}
}
在js程序编写中,能将函数作为参数或返回值的高阶函数比普通函数要灵活许多。比如除了相对普通的函数调用返回外,还可以形成一种后续传递风格的结果接收方式,而非单一的返回值形式。后续传递风格的程序编写将函数的业务重点从返回值转移到了回调函数中:
function foo( x, fn ) {
return fn( x );
}
function bar( y ) {
return y*3;
}
console.log( foo( 10, bar ) ); // 30
foo
函数中的参数fn
就是一个回调函数。在调用foo()
时可以传入bar
函数作为后续处理业务的回调函数。传入bar
函数中的参数不同,可以得到不同的结果。
foo就是一个高阶函数,类似这样的在js中很常见,比如数组的sort()
、forEach()
、reduce()
等。
高阶函数可以十分方便的对复杂业务进行解耦,事件的程序编写就受益于此。
函数的灵活性除了普通函数、高阶函数,还体现在偏函数。通过指定部分参数来产生一个新的定制函数的形式就是偏函数。看下面示例:
var toString = Object.prototype.toString;
var isString = function (obj) {
return toString.call(obj) === "[object String]";
}
var isFunction = function (obj) {
return toString.call(obj) === "[object Function]";
}
上例两个判断函数中有重复代码toString.call(obj) === "[object xxxx]"
,如果要定义更多这样的判断函数,容易产生冗余代码。为解决这个问题,需要使用新函数,这个新函数可以如工厂一样批量创建一些类似的函数:
var toString = Object.prototype.toString;
// 偏函数
var isType = function (type) {
return function (obj) {
return toString.call( obj ) === "[object "+ type +"]";
}
}
//批量创建新的判断函数
var isString = isType("String");
var isFunction = isType("Function");
偏函数在异步编程中很常见。
补充一句,与偏函数容易混淆的有函数柯里化,它很少用到,有兴趣的可以自行谷歌,这里不做讨论(实际是我不想去看那玩意)。