什么是Generator
Generator和Promise一样也是es6提供的一种异步编程的解决方案。
promise通过把执行过程代码和结果处理的代码解藕来加强代码的可读性,Generator就是直接让我们使用同步的语法来完成异步处理。为啥要这么做呢,因为人类更能理解同步的思维。
那么Generator是怎么做到的呢?因为Generator 函数可以暂停执行和恢复执行
首先,我们看看最基本的Generator函数是什么样的?
function * gen() {
console.log('执行');
}
gen();
看起来就是在function关键字和函数名之间加了一个*号,那么generator函数是怎么执行的呢?
它和普通的函数执行方式是一样的,也是使用函数名加一对括号进行调用,不同的地方在于当我们执行generator函数时,generator函数体并没有执行,而且会返回一个迭代器对象
可以声明一个变量let g接收gen()返回的值
let g = gen();
当我们调用g.next()函数的时候,generator函数才会执行。
刚刚讲过generator函数是可以暂停执行和恢复执行的,在generator函数内可以使用yield语句,当遇到yield语句,就暂停执行后面的操作,并将紧跟在yield后面的那个表达式的值,作为返回的对象的value属性值。
function * gen() {
yield 1;
}
let g = gen(); // 返回一个迭代器对象
当执行next函数的时候,
console.log(g.next()); // { value: 1, done: false }
会返回一个对象{value: "a", done: false},'a'就是g函数执行到第一个yield语句之后得到的值,false表示generator函数还没有执行完,只是在这暂停
如果再写一行gen.next();呢?
返回{value: undefined, done: true} done为true,代表generator函数执行完了。
另外generator函数也是可以使用return语句的,
function * gen() {
yield 1;
return 2;
}
let g = gen(); // 返回一个迭代器对象
console.log(g.next()); // { value: 1, done: false }
console.log(g.next()); // { value: 2, done: true }
执行第二个next函数时,会返回一个对象,value属性为return语句返回的值,done为true,代表函数执行完毕
如果继续执行next函数呢,也不会报错,会返回{ value: undefined, done: true }
实际上next函数还可以接受参数,这个参数就是是上一个yield语句返回的值,注意,是上一个yield语句返回的值哦。
function * gen() {
let a = yield 1;
console.log(a);
yield a;
}
let g = gen(); // 返回一个迭代器对象
console.log(g.next()); // { value: 1, done: false }
console.log(g.next(10)); // { value: 2, done: true }
如果给第一个next函数传参,什么都不会发生,因为这个参数是作为上一个yield语句的返回值的,既然是第一个next函数,说明上面没有yield语句了,传的参数也没有变量接收
刚刚开始的时候,讲过generator函数是用于解决异步编程的,那么最后,我们使用generator函数写一个函数,用于处理异步请求,使用generator函数可以让我们按照同步的语法来完成异步处理
// ajax函数将返回Promise对象:
function mockAjax(method, url, data) {
return new Promise(function (resolve) {
setTimeout(() => {
const result = {status: 100, msg: 'success', data}
resolve(result)
},1000);
});
}
function *gen() {
let role = yield mockAjax('GET', '/role?userId=' + 1, {id: 1});
console.log('role', role);
let product = yield mockAjax('GET', '/product?roleId=' + role.id, [{title: '衣服'}]);
console.log('product', product);
}
function run(g) {
let it = g(), ret;
(function iterate(val) {
ret = it.next(val);
if(!ret.done) {
// 简单测试返回值是否是一个promise
if (ret.value instanceof Promise) {
// 等待promise返回
ret.value.then(iterate);
}
}
})();
}
run(gen);