之前一章说了generator函数yield的用法,看了之后完全不知道generator函数有什么用,毕竟一步步的next,还不如我直接调用函数。仔细看了书中的示例,总算是有了头绪。我们先看这段代码
var fetch = require('node-fetch')
function* gen() {
// 地址瞎写的别当真
var url = 'https://zheshiyigeurl.com'
var result = yield fetch(url)
console.log(result)
}
var g = gen()
g.next()
// 下面这个塞入回调函数 就变成同步了
g.next()
这里的fetch是一个异步操作,返回Promise对象。在我们第一次调用next的时候,fetch会被执行。第二次调用next的时候console.log会执行。而result会是一个Promise对象,在这种调用方式下,generator函数感觉就是废,不明所以。但我们想想,这种调用的精髓就在于yield的时候,gen函数是被暂停了,如果我们要实现同步操作,我们只需要等待足够的时间,确保异步操作已经完成后,再调用next就可以了。但问题的关键是我们怎么知道异步的fetch是在什么时候完成的呐。所以实现generator同步的关键点就变成了:
- 使用yield暂停函数
- 等待异步完成后再执行next函数
那么接下来就是谁能知道异步已经完成呐,答案很简单,异步自己才知道,也就是回调函数,当异步完成的时候,他会调用回调函数,那么我们要做的就是把next塞到异步回调函数中。
那么我们改改上面的函数,如下:
var fetch = require('node-fetch')
function* gen() {
// 地址瞎写的别当真
var url = 'https://zheshiyigeurl.com'
var result = yield fetch(url)
console.log(result)
}
var g = gen()
g.next().value.then((err, res) => {
g.next(res)
})
到这里我们有遇见了一个问题,那就是虽然gen函数变成同步函数了,但是我们外面的这个调用就很尴尬了,如果gen中有多个异步操作,那么外面的调用会陷入回调地狱中。类似于这样
g.next().value.then((err, res) => {
g.next(res).value.then((err, res) => {
g.next(res).value.then((err, res) => {
g.next(res).value.then(...)
})
})
})