Skip to content

Generator 异步应用

Published: at 08:00 AM

Generator异步应用

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

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

回调函数

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("出错了!!"));