JavaScript异步流程控制的前世此生

JavaScript

javascript在设计之初.为了不资源管理复杂问题(多个线程同时操做dom,以哪一个为准),所以被设计成为了单线程语言.javascript

提及异步就不得不提回调, 为了解决多重回调嵌套致使代码难以维护问题.javascript一直都在完善这个解决方案.html

在10多年中javascript 异步流程控制通过了java

callback -> event -> promise -> yield & co -> async await编程

Callback

ES6以前异步编程最经常使用的方法,若是回调函数嵌套层数较深,代码将变得难以维护.而且在回调函数以外没法捕获回调函数中的异常.promise

var fs = require('fs')

try {
  fs.readFile('file', 'utf8', function(err, data){
    // if (err) {
    // console.log(err)
    // } else {
      console.log(data)
    // }
  })
} catch(e) {
  console.log(e)
}  
复制代码

尝试读取一个不存在的文件时.外层的try/catch 没法捕获这一异常.将输出 undefine. callback异步操做,异步调用的本体和callback属于不一样的事件循环.而try/catch 只能捕获当前事件的异常.所以将没法捕获dom

Event (发布/订阅模式)

采用事件驱动模式.任务的执行不取决于代码的顺序,由某个事件来决定异步

var EventEmitter = require('events') 
var fs = require('fs')

var eve = new EventEmitter()

// 监听read事件
eve.on('read', function(value){
  console.log(value)
})
// 执行一个异步读取
fs.readFile('./template.txt', 'utf8', function (err, data) {
  if (err) {
    console.log(err)
  } else {
    // 拿到数据后 发送一个read事件.并传递数据 
    eve.emit('read', data)
  }
})

复制代码

Promise

在ES6中提供了promise对象.给外界提供了统一的API.可用同步操做的流程来表达异步操做.避免了callback 中的嵌套层数过深,不便维护的弊端.async

var fs = require('fs')

function read (path) {
  return new Promise(function(resolve, reject){
    fs.readFile(path, 'utf8', function(err, data){
      if (err) {
        reject(err)
      } else {
        console.log(data)
        resolve()
      }
    })
  })
}

read('./1.txt').then(function(){
  return read('./2.txt')
}).then(function(){
  return read('./3.txt')
}).then(function(){
  console.log('执行结束')
})
复制代码

yield && co

经过Generator函数封装异步任务.在须要暂停的地方使用yield异步编程

var fs = require('fs')

function *getData () {
 var a = yield readFile('./1.txt')
 console.log(a)
 var b =  yield readFile('./2.txt')
 console.log(b)
 var c =  yield readFile('./3.txt')
 console.log(c)
}

function readFile(path) {
  return new Promise(function(resolve, reject){
    fs.readFile(path, 'utf8', function (err, data) {
      if (err) {
        reject(err)
      } else {
        resolve(data)
      }
    })
  })
}

function co(gen) {
  var fn = gen()
  var lastVal
  return new Promise(function(resolve, reject){
    !function next(lastVal) {
      var {value, done}  = fn.next(lastVal)
      if (done) {
        resolve()
      } else {
        value.then(next, reject)
      }
    }()
  })
}

co(getData)
复制代码

async/await

Async/Await应该是目前最简单的异步方案了函数

  • async 表示这是一个async函数,await只能用在这个函数里面
  • await 表示在这里等待promise返回结果了,再继续执行。
  • await 后面跟着的应该是一个promise对象(其余返回值也能够,只是会当即执行)
  • 捕获错误
var fs = require('fs')

async function getData () {
  try {
    var a = await readFile('file')
  } catch(e) {
    console.log(e)
  }  
  var b =  await readFile('./2.txt')
  console.log(b)
  var c =  await readFile('./3.txt')
  console.log(c)
}

function readFile(path) {
  return new Promise(function(resolve, reject){
    fs.readFile(path, 'utf8', function (err, data) {
      if (err) {
        reject(err)
      } else {
        resolve(data)
      }
    })
  })
}

getData()
复制代码

参考文章 Generator 函数的含义与用法

相关文章
相关标签/搜索