-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Description
对于Generator,个人感觉至少要先掌握两个点:
一是Generator的“惰性”的特点,是一种暂停执行的函数。
二是next方法可以带参数,参数作为上一yield的返回值。
如果完全不理解,建议先看Generator的基本语法,这里只给两个例子,简单的过一遍这两个点。
// Generator的执行不是自动的,他需要调用next方法,来推动执行
function* g1 () {
yield 'hello'
yield 'world'
return 'ending'
}
var test1 = g1() // 调用g1,返回的不是函数运行结果,而是一个指向内部状态的指针对象
test1.next() // Object {value: "hello", done: false}
test1.next() // Object {value: "world", done: false}
test1.next() // Object {value: "ending", done: true} 到这一步done的值为true,已经执行完了
test1.next() // Object {value: undefined, done: true} 再怎么执行 都是返回这个
// next方法带参数 和 不带参数
function* g2(x) {
var y = 2 * (yield (x + 1));
var z = yield (y / 3);
return (x + y + z);
}
var test2 = g2(5)
test2.next()
// 步骤 (x + 1) => (6 , 未执行完)
// 结果 Object{value: 6, done: false}
test2.next()
// 步骤 (y = 2 * undefined) => (y / 3) => (NaN, 未执行完)
// 结果 Object{value:NaN, done: false}
test2.next()
// 步骤 (z = undefined) => (5 + NaN + undefined) => (NaN, 执行完)
// 结果 Object{value:NaN, done: true}
var test3 = g2(5)
test3.next()
// 步骤 (x + 1) => (6 , 未执行完)
// 结果 Object{value: 6, done: false}
test3.next(12)
// 步骤 (y = 2 * 12) => (y / 3) => (8, 未执行完)
// 结果 Object{value:8, done: false}
test3.next(13)
// 步骤 (z = 13) => (5 + 24 + 13) => (42, 执行完)
// 结果 Object{value:42, done: true}
好的,Generator太懒了,要手动next才能一步步执行,很麻烦,那么我们让他自动执行。
var step1 = () => 100
var step2 = val => val + 2
var step3 = val => val + 3
var step4 = val => val + 4
function* g3() {
try {
var val1 = yield step1()
var val2 = yield step2(val1)
var val3 = yield step3(val2)
var val4 = yield step4(val3)
// Do something with val4
console.log(val4)
} catch (e) {
// Handle any error from step1 through step4
}
}
// 自动执行
var test4 = g3()
var res = test4.next()
while(!res.done){
res = test4.next(res.value)
}
可以看的出,我们的g3的代码非常的清晰:想要获取step1的值,作为参数给step2,以此类推,依赖于val1, val2, val3 得出val4,并对val4进行后续操作。
那么,我们想把g3这种清晰酷炫的写法运用到异步上,【让异步写起来像同步】可以吗?然而必须保证前一步执行完,才能执行后一步的话,上面这个自动执行部分的写法就不适用于异步操作。
先引用个阮老师es6教程给的例子
const fetch = require('node-fetch')
// 这段代码非常像同步操作,除了加上了yield命令。
function* g4(){
let url = 'https://api.github.com/users/github'
let result = yield fetch(url)
console.log(result.bio)
}
// 执行上述代码的方法,让generator自动跑起来。
var test5 = g4()
var result = test5.next()
result.value
.then((data) => data.json())
.then((data) => {test5.next(data)})
虽然 Generator 函数将异步操作表示得很简洁,但是流程管理却不方便(即何时执行第一阶段、何时执行第二阶段)。
但是我们却可以把流程这部分的操作总结出规律:当获取到该步的值val1时,则调用next并把val1传递;当获取到下一步的值val2时,则调用next并把val2传递。这是个始终在获取到值后,再进行下一步操作的过程。因此
function run(gen){
var g = gen()
function next(data){
var result = g.next(data)
if (result.done) return result.value
result.value.then(function(data){
next(data)
})
}
next()
}
run(g4)
下一篇
Metadata
Metadata
Assignees
Labels
No labels