002 Generator 函数
CENSWIN 7/18/2021 Javascript
协程: 意思是多个线程互相协作,完成异步任务。
# 用法
Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同。语法上,Generator 函数是一个状态机,封装了多个内部状态。该在function关键字与函数名之间有一个星号。
Generator 函数最大的特点就是可以通过 yield关键字 暂停函数执行,交出控制权。函数体外则通过 next() 方法再次交回控制权
function* foo () {
const a = yield 2
return 88
}
const g = foo(); // 此时未执行,只生成对象
console.log(g.next()); // 第一次执行 // {value: 2, done: false}
console.log(g.next()); // 第二次执行 // {value: 88, done: true}
1
2
3
4
5
6
7
2
3
4
5
6
7
next 方法可以接收参数,这是向 Generator 函数体内输入数据,但第一次使用next方法传参是无效的,方法的参数表示上一个yield表达式的返回值
function* foo() {
const a = yield 2;
console.log(a); // 123
return 88;
}
const g = foo();
console.log(g.next()); // 第一次执行返回第一个 yield 表达式的值
console.log(g.next(123)); // 第二次执行 并传入123,改变了第一次执行的 a 的值
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
除了 next 方法还有 throw() 、 return()
throw()是将yield表达式替换成一个throw语句gen.throw(new Error('error')); // Uncaught Error: 出错了1return()是将yield表达式替换成一个return语句从而终止函数gen.return(2); // {value: 2, done: true}1
# 应用
# 单个异步任务
function* foo() {
let res = yield fetch("https://jsonplaceholder.typicode.com/todos/1");
console.log(res);
}
1
2
3
4
2
3
4
获取结果
const g = foo()
const result = g.next() // 第一次执行遇到yield, 返回 fetch 结果 {value: Promise, done: false}
result.value.then(data => {
return data.json(); // json格式化
}).then(res => {
// 拿到格式化后的数据,交回给 foo ,同时第二次执行 next 改变的是上一次的值,res 正常输出
g.next(res)
})
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 多个异步任务
function* foo() {
let res = yield fetch("https://jsonplaceholder.typicode.com/todos/1");
console.log("res1", res);
let res2 = yield fetch("https://jsonplaceholder.typicode.com/todos/2");
console.log("res2", res2);
}
1
2
3
4
5
6
2
3
4
5
6
为了正常运行可能需要链式调用then
const g = foo();
const result1 = g.next();
result1.value.then((res) => {
return res.json();
}).then((data) => {
return g.next(data).value; // 返回promise对象
}).then((res) => {
return res.json();
}).then((data) => {
return g.next(data);
});
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
有更好的方法吗?可以使用递归编写一个启动器,让 Generator 函数自动运行 (dva.js -- effect)
function run(gen) {
var g = gen();
function next(data) {
var result = g.next(data);
if (result.done) return;
result.value.then(function (data) {
return data.json();
}).then(function (data) {
next(data);
});
}
next();
}
run(foo); // 传入 Generator 函数 自动执行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
参考: 小小小十七 (opens new window) 阮一峰 (opens new window) 阿里云云栖号 (opens new window)