精华 yield方式的异步代码什么原理?(刨根向)
发布于 1 年前 作者 captainblue2013 3768 次浏览 最后一次编辑是 8 个月前 来自 分享

江湖上流传着一个说法,说是通过 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有一个很特别的能力——移花接木。

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

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

君子无罪,怀璧其罪

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

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

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

我们看看成品代码:

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方式的异步代码 原理解释

(未完)

原文地址: 开发者小蓝

16 回复

感谢管理员

根的还不太深

@13241491189 请赠我一把洛阳铲 自豪地采用 CNodeJS ionic

我以为要刨到yield syntax在v8的实现上。。

这里有篇文章,相当好用,和本文有异曲同工之妙~@寸志 ES6 Generator

我说在哪里见过,原来是你转载自己的文章~~

卧槽。蓝神,抱紧大腿。

感觉阮一峰的es6电子书里讲得,比较详细和深入

哈哈。借楼主的广告位 https://github.com/berwin/Blog/issues/8 关于Koa,co,generator我见过最好的一篇文章,没有之一

bable 转换成switch case 实现多次返回值

好文笔,好想象力

回到顶部