异步编程
函数式编程
高阶函数
在通常的语言中,函数的参数只接受基本的数据类型或者是对象引用,返回值只能是基本数据类型和对象引用。
function foo(x) {
return x
}
高阶函数是把函数作为参数,将函数作为返回值的函数
function foo(x) {
return function () {
return x
}
}
高阶函数可以将函数作为输入或者返回值的变化
偏函数用法
偏函数用法是指创建一个调用另外一个部分(参数或者变量已经预置的函数)的函数的用法
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]'
}
在JavaScript中进行类型判断的时候,通常会进行类型上述代码的方法进行定义,但是上面的代码出现了冗余代码,为了解决重复定义的问题,引入一个姓的函数,这个新的函数可以和重唱一样批量创建类似的函数
var isType = function(type) {
return function (obj) {
return toString.call(obj) == '[object' + type + ']'
}
}
var isString = isType('String')
var isFunction = isType('Function')
== 这种通过指定部分参数类产生一个新的定制函数的形式叫偏函数==
异步编程的优势和难点
node带来的最大特性:事件驱动的非阻塞I/O模型。非阻塞io可以使得cpu和io并不相互依赖等待,让资源得到更好的利用,对于网络引用而言,并行带来的想象空间更大
如果采用传统的同步io模型,分布式计算中的性能会大打折扣
难点
异常处理
异步io的实现主要包括两个阶段,提交请求和处理结构,这两个阶段中又事件循环的调度,两者互不关联,异步方法通常在第一个阶段请求后立即返回,因为异常不一定发生在这个阶段。
var async = function(callback) {
process.nextTick(callback)
}
调用async()方法后,callback被存储起来,直到下一次tick才会取出来,尝试用异步方法进行try/catch操作只能捕获档次时间循环内的一场,对于callback执行时抛出的异常无能为力
try {
async(callback)
}catch(e) {
//todo
}
node在一场处理上形成了一种约定: 将异常作为回调函数的第一个实参传回,如果是空值,则表明调用没有异常抛出
async(function (err, results) {
//todo
})
- 必须执行调用者传入的回调函数
- 正确传递回异常供调用者判断
var async = function(callback) {
process.nextTick(function() {
var results = something
if(error) {
return callback(error)
}
callback(null, results)
})
}
在异步方法的编写中,另一个容易犯的错误是对用户传递的回调函数进行异常捕获
- 错误
try {
req.body = JSON.parse(buf, options.reviver)
callback()
} catch(err) {
err.body = buf;
err.status = 400
callback(err)
}
- 正确
try {
req.body = JSON.parse(buf,options.reviver)
} catch(err) {
err.body = buf;
err.status = 400
return callback(err)
}
callback()
函数嵌套过深
dom事件相对而言不会存在相互依赖或者需要多个事件一起写作的场景,较少出现异步多级依赖的情况,但是对于node而言,事务中存在多个异步调用的场景
fs.readdir.join(__dirname, '..'), function(err, files) {
files.forEach(function(filename, index){
fs.readFile(filename, "utf8",function(err, file) {
})
})
}
阻塞代码
node中没有sleep()
var start = new Date()
while(new Date() - start < 1000 ) {
// todo
}
// 需要阻塞的代码
这段代码是糟糕的,会一直占用cpu进行判断,并不能让进程沉睡
多线程编程
在谈论JavaScript的时候,通常是单一线程上的代码,浏览器中指的是JavaScript执行线程和ui渲染共用的一个线程,在node中,没有ui渲染的部分。模型基本相同,对于服务器端,单个node不会充分利用多核cpu的,web workers 通过对JavaScript执行和ui渲染分开,更好的利用了多核cpu进行大量运算。
前端浏览器对于标准的之后性,web worker没有应用起来。web worker能利用cpu喝减少阻塞ui渲染,但是不能解决ui渲染的效率问题,node借鉴了这个模式。
异步转同步
node中同步编程,不能得到原生手段的支持,需要借助库或者编译手段来实现。对于异步调用,存在良好的流程控制。