Skip to content

Instantly share code, notes, and snippets.

@zyf0330
Last active June 15, 2017 06:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zyf0330/da21e0591d6d0ea94baaec4b0f6261fa to your computer and use it in GitHub Desktop.
Save zyf0330/da21e0591d6d0ea94baaec4b0f6261fa to your computer and use it in GitHub Desktop.
Wrap generator returns promise. Got by myself
const wrapGenerator = function (Generator) {
const promise = new Promise(function (resolve, reject) {
const g = Generator()
let r = g.next()
const nextYield = function (r) {
if (r.done == true) {
resolve(r.value)
return
}
r.value.then(function (x) {
r = g.next(x)
nextYield(r)
}).catch(function (e) {
g.throw(e)
})
}
nextYield(r)
});
return promise
}
// 转换 Generator 为普通函数
const convertGenerator = function (Generator) {
const handleFunc = function (Generator) {
const s = Generator.toString()
const lines = s.split('\n').slice(1, -1)
const appendBrackets = []
for (let i = 0; i < lines.length; i++) {
const line = lines[i]
const match = line.match(/\s*(?!const|let|var)\s+?([\w0-9_]+?)\s*=\s*yield\s+?(.+)/)
if (match == null) {
continue
}
const declare = match[1]
const yieldIn = match[2]
const yieldFunc = 'yield'
lines[i] = `${yieldFunc}(${yieldIn}, function (${declare}) {`
appendBrackets.push('})')
}
const newS = lines.concat(appendBrackets).join('\n')
// const newF = new Function(newS)
return `(function (){${newS}})`
}
return function () {
// 处理 func,在这里使用 eval 才能使得 g 处于当前作用域
const g = eval(handleFunc(Generator))
// yielding 应该是一个随着 try/catch 层级深入而嵌套的数据结构,才能正确使用生成器 throw 方法
// 此处简单看作没有 try/catch 的情形
let yielding = {in: undefined, out: g};
const yield = function (yieldInValue, yieldOutCb) {
yielding = {
in: yieldInValue,
out: yieldOutCb
}
}
g.next = function (value) {
const yieldOutCb = yielding.out
yielding = null
const returnValue = yieldOutCb(value)
const done = yielding == null
return {
value: done ? returnValue : yielding.in,
done: done
}
}
return g
}
}
const fetch1 = function (g) {
return Promise.resolve('fetch1')
}
const fetch2 = function (g) {
return Promise.resolve('fetch2')
}
const Generator = function *() {
console.log('before first yield statement')
const u1 = yield fetch1()
const u2 = yield fetch2()
console.log('inner done', 'u1', u1, 'u2', u2)
return 'outer done'
}
console.log('origin Generator')
wrapGenerator(Generator).then(function (x) {
console.log(x, '\n')
console.log('converted ....')
wrapGenerator(convertGenerator(Generator)).then(function (x) {
console.log(x)
})
})
@zyf0330
Copy link
Author

zyf0330 commented Jun 15, 2017

添加将 Generator 转换为普通函数。
这里只考虑简单的单一作用域代码块,因此也不考虑异常捕获。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment