# Generator异步应用

异步操作,一个任务不是连续完成的,先执行一段,转而执行其他任务,等做好了准备,再回过头执行第二段。

ES6之前的异步操作,大致以下四种:

  • 回调函数
  • 事件监听
  • 发布/订阅
  • Promise对象

# 回调函数

const fs = require('fs');

// 回调函数
fs.readFile('./data1.json', 'utf-8', function (err, data) {
  console.log(err)
  console.log(data)
})


// 回调地狱出现 callback hell
fs.readFile('./data1.json', 'utf-8', function (err, data) {
  console.log(err)
  console.log(data)

  fs.readFile('data2.json', 'utf-8', function (err2, data2) { 
    console.log(err2)
    console.log(data2)
  })
})

# Promise

Promise的出现是为了解决回调地狱,将函数回调改为链式调用。采用Promise连续读取多个文件。

const readFilePromise = require('fs-readfile-promise')

// 返回promise的readFile
readFilePromise('data1.json', 'utf-8').then(function(data) {
  console.log('readFilePromise-1', data)
}).then(function () { 
  return readFilePromise('data21.json', 'utf-8')
}).then(function (data) {
  console.log(data.toString())
}).catch(function (err) {
  console.log(1, err)
})

用Promise写要将原来的代码包上一层Promise,会显得有些冗余,同时会出现一堆then的处理。

# Generator函数

function* gen(x) {
  var y = yield x + 2;
  return y;
}
 
var g = gen(1)
console.log(g.next())
console.log(g.next())

上面的代码中,调用Generator函数会返回一个指针(即遍历器)g,调用g.next方法,指针指向第一个遇到的yield语句。

const readFilePromise = require('fs-readfile-promise');
const fs = require('fs')

function* asyncJob() {
  var data = yield readFilePromise('data1.json', 'utf-8');
  return data
}

var job = asyncJob();
var res1 = job.next()
// res1返回{value: Promise{<pending>, done: false}}
res1.value.then(function (data) {
  console.log(data)
})

var res2 = job.next();
console.log(res1)
console.log(res2)

Generator函数是协程在ES6的实现,最大的特点就是可以交出函数的执行权(即暂停执行)。

整个Generator函数就是一个封装的异步任务,或者说是异步任务的容器。异步操作需要暂停的地方,都用yield语句注明。

Generator函数的数据交换和错误处理。Generator函数可以暂停执行和恢复执行,这是它能封装异步任务的根本原因。

除此之外,它还有两个特性,使他可以作为异步编程的完整解决方案:

  • 函数体内外的数据交换
  • 错误处理机制
// 数据交换
function* genV2(x) {
  var y = yield x + 2;
  return y;
}

var g2 = genV2(1);
console.log(g2.next())
console.log(g2.next(20000))

// 错误处理
function* genV3(x) {
    try {
    // throw new Error()
    var y = yield x + 2;
  } catch (e) {
    console.log(1, e)
  }
}

var g3 = genV3(1)
console.log(g3.next())
console.log(g3.throw('出错了!!'))
Last Updated: 2019-09-26 19:30:00