当前位置: 代码迷 >> 综合 >> Generator 函数的介绍和使用
  详细解决方案

Generator 函数的介绍和使用

热度:7   发布时间:2023-11-29 12:35:17.0

Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同。

异步编程对 JavaScript 语言太重要。JavaScript 语言的执行环境是“单线程”的,如果没有异步编程,根本没法用,非卡死不可。

ES6 诞生以前,异步编程的方法,大概有下面四种。

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

什么是异步?

所谓"异步",简单说就是一个任务不是连续完成的,可以理解成该任务被人为分成两段,先执行第一段,然后转而执行其他任务,等做好了准备,再回过头执行第二段。

比如,有一个任务是读取文件进行处理,任务的第一段是向操作系统发出请求,要求读取文件。然后,程序执行其他任务,等到操作系统返回文件,再接着执行任务的第二段(处理文件)。这种不连续的执行,就叫做异步。

相应地,连续的执行就叫做同步。由于是连续执行,不能插入其他任务,所以操作系统从硬盘读取文件的这段时间,程序只能干等着。

promise解决异步缺点?

promise允许将回调函数的嵌套,改成链式调用。

// 读取文件信息
const fs = require('fs')const promise = new Promise((resolve, reject) => {fs.readFile('./01.txt', (err, data) => {if (err) return reject(err)resolve(data)})
})promise.then(val => {console.log(val.toString());return new Promise((resolve, reject) => {fs.readFile('./02.txt', (err, data) => {if (err) return reject(err)resolve(data)})})
}).then(val => {console.log(val.toString());return new Promise((resolve, reject) => {fs.readFile('./03.txt', (err, data) => {if (err) return reject(err)resolve(data)})})
}).then(val => {console.log(val.toString());
})
// 捕获错误
.catch(err => {console.log(err);
})

Promise 提供then方法加载回调函数,catch方法捕捉执行过程中抛出的错误。

可以看到,Promise 的写法只是回调函数的改进,使用then方法以后,异步任务的两段执行看得更清楚了,除此以外,并无新意。

Promise 的最大问题是代码冗余,原来的任务被 Promise 包装了一下,不管什么操作,一眼看去都是一堆then,原来的语义变得很不清楚。

Generator 函数

说到这里我们先需要明白一个概念协程

传统的编程语言,早有异步编程的解决方案(其实是多任务的解决方案)。其中有一种叫做"协程"(coroutine),意思是多个线程互相协作,完成异步任务。

协程有点像函数,又有点像线程。它的运行流程大致如下。

  • 第一步,协程A开始执行。
  • 第二步,协程A执行到一半,进入暂停,执行权转移到协程B
  • 第三步,(一段时间后)协程B交还执行权。
  • 第四步,协程A恢复执行。

上面流程的协程A,就是异步任务,因为它分成两段(或多段)执行。

function* helloWorld(world) {var a = yield 'hello' + worldreturn a
}
const hw = helloWorld('world')
console.log(hw.next());  // {value: 'helloworld', done: false}
// 向内输入一个数据
console.log(hw.next(1));  // {value: undefined, done: true}

next方法的作用是分阶段执行Generator函数。每次调用next方法,会返回一个对象,表示当前阶段的信息(value属性和done属性)。

表示当前阶段的值;done属性是一个布尔值,表示 Generator 函数是否执行完毕,即是否还有下一个阶段。

next返回值的 value 属性,是 Generator 函数向外输出数据;next方法还可以接受参数,向 Generator 函数体内输入数据。

异步任务的封装

 下面我们通过Generator 函数,来执行一个真实的异步任务。

var fs = require('fs');var readFile = function (fileName){return new Promise(function (resolve, reject){fs.readFile(fileName, function(error, data){if (error) return reject(error);resolve(data);});});
};var gen = function* (){var f1 = yield readFile('01.txt');var f2 = yield readFile('02.txt');console.log(f1.toString());console.log(f2.toString());
};var g = gen();g.next().value.then(function(data){g.next(data).value.then(function(data){g.next(data);});
});
  相关解决方案