sun*_*uan 1 javascript ecmascript-6 redux redux-saga
假设我们有以下生成器函数:
function* testGenerator() {const result = yield Promise.resolve('foobar').then(res => res);console.log(result);}
如果我使用以下行运行此生成器,它会记录 undefined
const test = testGenerator();
test.next();
test.next();
Run Code Online (Sandbox Code Playgroud)
但在传奇中,这样的线路会记录下来foobar.我只是好奇这背后的机制是什么(将yield的结果赋给变量)
编辑:
TL; DR:
使用参数调用next()方法将恢复生成器函数执行,替换使用next()中的参数暂停执行的yield语句
基本上,要使其记录"foobar",只需将第一个yield的值传递给第二个yield,这样当它恢复时,yield语句将替换为值:
function* testGenerator() {
const result = yield Promise.resolve('foobar');
console.log(result);
}
const test = testGenerator();
test.next().value.then(r => test.next(r))
Run Code Online (Sandbox Code Playgroud)
代码审查
首先,摆脱这个; 它没有做任何事情
const result = yield Promise.resolve('foobar').then(res => res);Run Code Online (Sandbox Code Playgroud)
你的发电机工作正常
如果我使用以下行运行此生成器,它将记录未定义
不,不.它{next, value}每次都会记录一次
function* testGenerator() {
const result = yield Promise.resolve('foobar');
console.log(result);
}
let test = testGenerator()
console.log(test.next())
// { value: Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: 1}, done: false }
console.log(test.next())
// { value: undefined, done: true }Run Code Online (Sandbox Code Playgroud)
记录承诺是棘手的.如果你不相信我,请看这个
function* testGenerator() {
const result = yield Promise.resolve('foobar');
console.log(result);
}
let test = testGenerator()
test.next().value.then(console.log)
// "foobar"Run Code Online (Sandbox Code Playgroud)
协同程序
但是在传奇中,这样的线条会记录foobar.我只是好奇这背后的机制是什么(将yield的结果赋给变量)
Redux Saga可以通过发电机进行操作并处理各种效果.承诺只是你可以屈服的众多事情之一.
这是一个简单的协同程序函数的示例,该函数接受生成器实例并期望在最后一个结果之前产生Promises.注意双向数据流.
yield 从发电机发送数据gen.next(x) 将下一个值发送到生成器因此,我们正在利用这种能力的发电机送承诺出去,并发送承诺的决心回值的,这使得解决承诺的价值将被直接分配给一个变量
const coro = gen => {
const next = x => {
const {value, done} = gen.next(x)
if (done)
return value
else
return value.then(next)
}
return next()
}
function* testGenerator () {
const x = yield Promise.resolve(1)
console.log(x) // 1
const y = yield Promise.resolve(2)
console.log(y) // 2
const z = yield Promise.resolve(3)
console.log(z) // 3
return x + y + z
}
coro(testGenerator()).then(console.log)
// "6"Run Code Online (Sandbox Code Playgroud)
async & await
现在您已了解这一点,您完全理解提议async/ await工作的功能 - 下一个代码段的功能可能会因浏览器的支持而有所不同.
变化:
coro帮手async关键字而不是生成器function*await关键字代替yield行为是一样的.
await发送出去的承诺await调用async函数隐式返回一个Promise,因此链接一个.then调用以获取最终的值const testRoutine = async () => {
const x = await Promise.resolve(1)
console.log(x) // 1
const y = await Promise.resolve(2)
console.log(y) // 2
const z = await Promise.resolve(3)
console.log(z) // 3
return x + y + z
}
testRoutine().then(console.log)
// "6"Run Code Online (Sandbox Code Playgroud)
本土协同程序
你不应该推出自己的协同程序,因为有很多东西需要注意.例如,如果生成器throw是一个Error或yieldsa拒绝了Promise,那么上面的实现只会吞下它.
为了演示目的,我将向您展示如何更多地说明它,但如果您有兴趣覆盖所有基础,您应该阅读Redux Saga源代码,或者像tj这样的另一个协程库的源代码/ CO
const coro = gen => {
return new Promise((resolve, reject) => {
const next = x => {
try {
let {value, done} = gen.next(x)
return done ? resolve(value) : value.then(next, reject)
}
catch (err) {
reject(err)
}
}
next()
})
}
function* noYield() { return 5 }
function* throwsUp() { throw Error("OOPS") }
function* yieldReject() { yield Promise.reject('NO') }
function* normal() { let x = yield Promise.resolve(16); return x * x; }
coro(noYield())
.then(console.log, console.error) // 5
coro(throwsUp())
.then(console.log, console.error) // [Error: OOPS]
coro(yieldReject())
.then(console.log, console.error) // "NO"
coro(normal())
.then(console.log, console.error) // 256Run Code Online (Sandbox Code Playgroud)