IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    yield方式的异步代码什么原理?(刨根向)

    captainblue2013发表于 2016-06-30 03:39:16
    love 0

    江湖上流传着一个说法,说是通过 yield 和 generator ,就是用同步的方式写出异步的代码。

    真的是这样吗?

    也许你可以从网上搜到很多相关教程,照着样例代码,你也能写出这样的代码。但是你是否真的已经明白,这背后到底发生了什么?

    第一集,他是谁?

    这就是一个 generator,

    var gen = function* (){
    	return 1;
    }
    

    看上去像个函数,浑身有一种莫名其妙的的罪恶感,对了,他让我想起那恶心的指针。

    我们看看运行起来会怎么样?

    gen();
    // {}
    

    看来只是长得像,跟函数没啥关系呢。

    我想他还有其他不为人知的地方,比如,next()

    var a = gen();
    console.log( a.next() );
    
    // { value: 1, done: true }   duang!!
    

    我明白了,要调用next才能让他执行起来。

    第二集,yield ?

    如果 generator 遇上 yield 会怎样?

    var gen = function* (){
    	yield 2;
    	return 1;
    }
    var a = gen();
    console.log( a.next() );
    // { value: 2, done: false }
    

    他并没有返回1,而是2 ,一个被 yield了的2 。

    那么这个done的值,应该就是告诉我还没执行完的意思吧。

    那我能不能多next几次?

    var a = gen();
    console.log( a.next() );
    // { value: 2, done: false }
    console.log( a.next() );
    // { value: 1, done: true }
    console.log( a.next() );
    // { value: undefined, done: true }
    

    果然,只要done没返回 true 就可以一直 next下去。(注:false也可以继续next,不过已经没有什么意义了 )

    一个典型的迭代器呼之欲出 !

    没错,generstor就是一个迭代器,暂时来说和异步编程没有任何关系

    var item = null;
    while( item = a.next() ){
    	if(item.done === true){
    		break;
    	}
    	// do anything with {item}
    	console.log(item.value);
    }
    
    // 2 , 1
    

    第三集,Promise 和 CO

    generator的诞生就是为了成为一个伟大的迭代器,阴差阳错之下,被用来写异步代码。 这得从他遇上 promise 说起。

    generator,或者说 yield有一个很特别的能力——移花接木。

    alt

    一个 yield 表达式包含很丰富的操作,一行代码包含了两个阶段逻辑

    • 执行最右边的操作 2+3 ,把结果通过value带出去。(next 的返回值)
    • 再次调用next时,可以接受参数,将外面的值传进来,赋值给 a

    君子无罪,怀璧其罪

    这种特异功能被眼尖的程序员发现了,一个伟大的设想诞生了。

    • 先将异步操作用promise实现,通过yield带出去
    • 然后执行then函数,获取异步处理结果
    • 再次执行next,将异步结果传回 generator内部,赋值给yield左边的表达式

    alt

    如此一来,这一行代码看起来就像同步代码一样!

    我们看看成品代码:

    var gen = function* () {
      let content = yield httpGet('http://lanhao.name');
      return content;
    };
    
    var myCo = (fn) => {
      let state = null;
      let g = fn();
      return (function next(data){
    	 state = g.next(data);
    	 if(state.done){
    	  return state.value;
    	 }else{
    	  return state.value.then( val => next(val) );
    	 }
     })();
    };
    
    
    var a = myCo(gen);
    
    a.then(val=>console.log(val));
    
    //{"code":200,"data":[],"message":""}
    

    而且我们发现,不管generator逻辑如何,Co的写法都是一样的,不会重复编码。

    只要通过Co来执行generator,我们就能像同步代码一样写异步操作。

    以上就是 yield方式的异步代码 原理解释

    (未完)

    原文地址: 开发者小蓝



沪ICP备19023445号-2号
友情链接