为js中yield赋能

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,

「let money = yield 知乎赞赏」
赞赏
在JavaScriptyield*是一个关键字和表达式。yield*关键字用于将控制权委托给另一个生成器或可迭代对象。当使用yield*时,它会迭代并返回委托生成器或可迭代对象的每个值,直到迭代完毕。 例如,在下面的代码示例,函数g2委托给了函数g1,通过yield* g1(),函数g2会先返回自身的第一个值1,然后继续执行委托的函数g1,并返回g1的每个值,最后再返回g2的剩余值4。 ```javascript function* g1() { yield 2; yield 3; } function* g2() { yield 1; yield* g1(); yield 4; } var iter = g2(); console.log(iter.next()); // { value: 1, done: false } console.log(iter.next()); // { value: 2, done: false } console.log(iter.next()); // { value: 3, done: false } console.log(iter.next()); // { value: 4, done: false } console.log(iter.next()); // { value: undefined, done: true } ``` 另外,你还可以使用yield*表达式将控制权委托给其他生成器,并在委托生成器使用yield语句来产生值。在下面的代码示例,函数outer内部使用yield* next将控制权委托给函数inner,并可以通过yield语句在inner产生值。结果是,在调用gen.next()两次后,会依次返回'open'、'hello'、'world'和'close'。 ```javascript function* outer(next) { yield 'open'; yield* next; yield 'close'; } function* inner() { yield 'hello'; a = 2; yield 'world'; } gen = outer(inner()); console.log(gen.next()); // { value: 'open', done: false } console.log(gen.next()); // { value: 'hello', done: false } console.log(gen.next()); // { value: 'world', done: false } console.log(gen.next()); // { value: 'close', done: false } ``` 总结来说,yield*在JavaScript用于将控制权委托给其他生成器或可迭代对象,并可以通过yield语句在委托生成器产生值。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值