# 异步编程

# 函数式编程

# 高价函数

  • 把函数作为参数,或者返回值是函数
  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')
_.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)
})
上次更新时间: 2019-12-24 2:17:04 PM