# 异步编程
# 函数式编程
# 高价函数
- 把函数作为参数,或者返回值是函数
var points = [40, 100, 1, 5, 32, 10]
points.sort(function(a, b) {
return a - b
})
// [1, 5, 10, 32, 40, 100]
- ECMAScript5
- forEach()
- map()
- reduce()
- reduceRight()
- filter()
- every()
- some()
# 偏函数
- 创建一个调用另外一个部分---参数或变量已经预置的函数----的函数的用法
// 判断对象的类型
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]'
}
//...
//改良
var isType = function(type) {
return function(obj) {
return toString.call(obj) == '[object + '+ type +']'
}
}
var isString = isType('String')
- 函数式编程js库 Underscore
_.after = function(times, func) {
if (times <= 0) return func()
return function() {
if (--times < 1) { return func.apply(this, arguments) }
}
}
# 异步编程的优势和难点
# 优势
- 事件驱动的非阻塞I/O模型,可以使cpu与I/O不会互相依赖等待
- 事件循环模型对应海量请求,作用在单线程上,要防止任何一个计算耗费过多的CPU时间片
- 建议对cpu的消耗不要超过10ms
- 将大量计算分解成诸多小计算,通过setImmediate()进行调度
# 难点
- 1.异常处理
- 2.函数嵌套过深
- 3.阻塞代码
- 4.多线程编程
- 5.异步转同步
# 1.异常处理
- 异步I/O的实现包括两个阶段:
提交请求
处理结果
彼此不关联
# 原则一:必须执行调用者传入的回调函数
# 原则二:正确传递回异常供调用者判断
# 2.函数嵌套过深
# 3.代码阻塞
- js 没有sleep()
var start = new Date()
while (new Date() - start < 1000) {
}
// 需要受阻塞的代码
- while 会持续占用cpu进行判断,破坏了事件循环的调度,占用了cpu资源,其余请求都会得不到响应
# 4.多线程编程 Web Workers
# 异步编程的解决方案
- 事件发布/订阅模式
- Promise/Deferred模式
- 流程控制
# 事件发布/订阅模式
发布/订阅模式
事件监听器模式是一种广泛用于异步编程的模式,是回调函数的事件化node 的 events 模块 是发布/订阅模式的一个简单实现,不存在事件冒泡、preventDefault()、stopPropagation()、stopImmediatePropagation() 等控制事件传递的方法
- addListener/on()
- once()
- removeListener()
- removeAllListeners()
- emit()
// 订阅 --- 高级函数的应用 emitter.on('event1', function(message) { console.log(message) }) emitter.emit('event1', 'I am message!')
# Promise/Deferred模式
var Promise = function() {
EventEmitter.call(this)
}
util.inherits(Promise, EventEmitter)
Promise.prototype.then = function (fulfilledHandler, errorHandle, progressHandler) {
if (typeof fulfilledHandler === 'function') {
// once 保证成功只回调一次
this.once('success', fulfilledHandle)
}
if (typeof errorHandler === 'function') {
this.once('error', errorHandler)
}
if (typeof progressHandler === 'function') {
this.on('progress', progressHandler)
}
return this
}
# async
# 异步的串行执行
async.series()
实现一组任务的串行执行
async.series([
function(callback) {
fs.readFile('./file1.txt', 'utf-8, callback)
},
function(callback) {
fs.readFile('./file2.txt', 'utf-8, callback)
}
], function(err, results) {
if (err) {
console.log(err)
return
}
console.log(results) // [file1.txt, fille2.txt]
})
// 同等
fs.readFile('./file1.txt', 'utf-8', function(err, content) {
if (err) {
console.log(err)
return
}
fs.readFile('./file2.txt', 'utf-8', function(err, content) {
if () {
console.log(err)
return
}
callback(null, [content, data])
})
})
# 异步的并行执行
async.parallel()
async.parallel([
function(callback) {
fs.readFile('file1.txt', 'utf-8', callback)
}
function(callback) {
fs.readFile('file2.txt', 'utf-8', callback)
}
], function(err, results) {
// results => [file1.txt, file2.txt]
})
# 异步调用依赖处理
async.waterfall()
async.waterfall([
function (callback) {
fs.readFile('./file1.txt', 'utf-8', function(err, content) {
callback(err, content)
})
},
function (args, callback) {
// args file1.txt
fs.readFile('./file2.txt', 'utf-8', function(err, content) {
callback(err, content)
})
}
], function(err, result) {
// result => file2.txt
})
# 异步并发控制
# bagpipe
-- push()
full()
- 通过一个队列来控制并发量
- 如果当前活跃的异步调用量小于限定值,从队列中取出执行
- 如果活跃调用达到限定值,调用暂时存放在队列中
- 每个异步调用结束时,从队列中取出新的异步调用
var Bagpipe = require('bagpipe')
// 设定最大并发数 - 10
var bagpipe = new Bagpipe(10)
for (var i = 0; i < 100; i++) {
bagpipe.push(async, function () {
// 异步回调执行
})
}
bagpipe.on('full', function (length) {
console.log('底层系统处理不能及时完成,队列拥堵,当前队列长度:' + length)
})