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 表示 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"}
看到了吗 我们可以操作yield后面的参数 和 其返回值之间的转换
来试试 让yield 直接提取异步接口返回的数据
假设我们有一个请求http接口函数 http.get(url) -> Promise Data Error 传递url返回数据
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())
这样我们就可以像写同步代码一样写异步代码了
为Generator赋能
上面铺垫了这么多就是为了在这里给yield赋能,经过yield之后的数据 都能得到我想要的数据,我把这个功能封装到一个函数里面 runIWant
实现的功能如下
let a = yield Promise data error -> 返回Promise 中的data
let b = yield Generator val -> 返回 Generator中的val (注:这里的val指的是Generator函数的返回值)
let c = yield 其它 -> 返回其它本身
let d = yield Nothing -> 直接退出运行 返回Nothing
如果Generator里面没有Promise data error 同步返回值否则返回Promise val error
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