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

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

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

回调函数

  1. const fs = require('fs');
  2. // 回调函数
  3. fs.readFile('./data1.json', 'utf-8', function (err, data) {
  4. console.log(err)
  5. console.log(data)
  6. })
  7. // 回调地狱出现 callback hell
  8. fs.readFile('./data1.json', 'utf-8', function (err, data) {
  9. console.log(err)
  10. console.log(data)
  11. fs.readFile('data2.json', 'utf-8', function (err2, data2) {
  12. console.log(err2)
  13. console.log(data2)
  14. })
  15. })

Promise

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

  1. const readFilePromise = require('fs-readfile-promise')
  2. // 返回promise的readFile
  3. readFilePromise('data1.json', 'utf-8').then(function(data) {
  4. console.log('readFilePromise-1', data)
  5. }).then(function () {
  6. return readFilePromise('data21.json', 'utf-8')
  7. }).then(function (data) {
  8. console.log(data.toString())
  9. }).catch(function (err) {
  10. console.log(1, err)
  11. })

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

Generator函数

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

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

  1. const readFilePromise = require('fs-readfile-promise');
  2. const fs = require('fs')
  3. function* asyncJob() {
  4. var data = yield readFilePromise('data1.json', 'utf-8');
  5. return data
  6. }
  7. var job = asyncJob();
  8. var res1 = job.next()
  9. // res1返回{value: Promise{<pending>, done: false}}
  10. res1.value.then(function (data) {
  11. console.log(data)
  12. })
  13. var res2 = job.next();
  14. console.log(res1)
  15. console.log(res2)

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

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

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

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

  • 函数体内外的数据交换
  • 错误处理机制
  1. // 数据交换
  2. function* genV2(x) {
  3. var y = yield x + 2;
  4. return y;
  5. }
  6. var g2 = genV2(1);
  7. console.log(g2.next())
  8. console.log(g2.next(20000))
  1. // 错误处理
  2. function* genV3(x) {
  3. try {
  4. // throw new Error()
  5. var y = yield x + 2;
  6. } catch (e) {
  7. console.log(1, e)
  8. }
  9. }
  10. var g3 = genV3(1)
  11. console.log(g3.next())
  12. console.log(g3.throw('出错了!!'))