yield是javascript关键字,被用来生成es6中的Generator,现在chrome的浏览器已经完美的支持了。
什么是Generator
我们写一个函数 在function后或前加* ,这个函数返回值就是Generator,这个函数称为Generator函数
function *main(){
}
main() // -> [object Generator]
function *learn(){
yield 1
yield 2
return 3
}
let learnGe = learn() // ->
Generator函数可以只运行函数的一部分,函数的剩余部分可以有使用者控制继续执行。
learnGe.next() // -> {"done": false, "value": 1}
done 为false表示 learn函数未运行完毕
value 表示 learn函数 yield 1中的 1
再次调用next()会运行到下一个 yield之处
learnGe.next() // -> {"done": false, "value": 2}
learnGe.next() // -> {"done": true, "value": 3}
最后运行之return之处 done为true ,value是return 的返回值
Generator的强大之处
前面的介绍根本体现不了yield的强大之处,有一个重点并没有介绍,它就是:
可以给learnGe.next函数传递参数 ,这个参数可以作为yield的返回值(注意:一定要动手实验)
function *withParam(){
let a = yield "a"
return a
}
let withParamGe = withParam()
let wr = withParamGe.next()
withParamGe.next("hello " + wr.value)
// -> {"done": true, "value": "hello a"}
由结果可知,给next传递参数可以控制"a"到变量a之间的转换。
一个很实用的地方,利用yield取出异步的『返回值』,使Generator函数看起来就像同步一样。
假设我们有一个http接口函数——http.get(url) -> Promise JSON Error 传递url返回Promise
function *mylogic(){
let data = yield http.get('/your/path')
your loginc ..
}
function runMyPromise(ge,val){
let a = get.next(val)
if(a.done){
return a.value
}else {
return a.then(data=>runMyPromise(ge,a.value))
}
}
runMyPromise(mylogic())
runMyPromise函数取出Promise中的data,通过Generator的特性赋值给 mylogic函数中的data,mylogic函数中的异步调用看起来就像同步一样简单。不,可以说就是同步代码了。
为Generator赋能
上面铺垫了这么多就是为了在这里给yield赋能,通过yield关键字,我们可以控制yield后面的表达式和yield前面赋值的关系——简单说就是控制怎样赋值的,如前面yield Promise是取出Promise中的data去赋值。除了Promise可能还想控制其它的赋值关系,我将它封装到一个函数中runIWant。
实现的功能如下
let a = yield Promise JSON Error -> 返回Promise 中的JSON
let b = yield Generator val -> 返回 Generator中的val (注:这里的val指的是Generator函数的返回值)
let c = yield 其它 -> 返回其它本身
let d = yield Nothing -> 直接退出运行 返回Nothing
如果Generator函数没有遇到Promise同步返回值,否则返回Promise中的data
function isPromise(a){
return Object.prototype.toString.call(a) === "[object Promise]"
}
function isGenerator(a){
return Object.prototype.toString.call(a) === "[object Generator]"
}
const Nothing = Symbol('Nothing')
const ToValue = Symbol('ToValue')
function isToValue(a){
return a && (typeof a[ToValue] === 'function')
}
function runIWant(ge,gval){
gval = gval || {done: false,value:undefined}
if ( gval.done) {
return gval.value
} else if (isPromise(gval.value)) {
return gval.value.then(data=>{
return runIWant(ge,ge.next(data))
})
} else if (isGenerator(gval.value)) {
return runIWant(ge,ge.next(runIWant(gval.value)))
} else if (gval.value === Nothing) {
return runIWant(ge,ge.return(Nothing))
}else {
return runIWant(ge,ge.next(gval.value))
}
}
(注:有些是手工输入打去的并没有经过测试,如果有错误请指出)
function *getName(){
let user = yield http.get('get/user')
return user.name
}
function *main(){
let name = yield getName()
console.log('My name is ' + name)
}
这些代码可以直接在chrome repl中运行 无需babel
备注:
Promise JSON Error 是指 Psomise类型 then取出的类型JSON,catch取出的类型是Error,