据说 ES6 的 Generator 是一个很神奇的函数,因此去了解了一下。 由于它不一样于以往的寻常函数,可是带来的体验却很是好 。这里首先讲了 Generator 是什么,分割线后面用了一个例子来讲明 Generator 到底好在哪里 ~ (能够选择性阅读~ )javascript
Generator 是一种异步编程解决方案,不明白?往下看 ~java
Generator 究竟是什么?官方文档是这样说的:“Generators are functions which can be exited and later re-entered. Their context (variable bindings) will be saved across re-entrances.”ajax
意思就是 Generator 函数内部的执行是能够暂停的。你可以执行到一半退出函数,同时执行到当前的上下文环境(包括变量等等)所有被保存下来,若是咱们稍后又进来继续执行下一段,此时是在上次状态的基础上继续往下执行。感受和别的函数很不同,如何去理解呢?编程
直接上代码:json
var myGen = function*(){ // 定义一个 Generator 函数 var one = yield 1; var two = yield 2; var three = yield 3; console.log(one,two,three); } var gen = myGen(); console.log(gen.next()); //第一次执行函数,输出 {value:1,done:false} console.log(gen.next()); //第二次执行函数,输出 {value:2,done:false} console.log(gen.next()); //第三次执行函数,输出 {value:3,done:false} console.log(gen.next()); //第四次执行函数,输出{value:undefined,done:true}
能够看到 function 后面加了一个 * 号,那是特有的 Generator 的写法,function* 就表示我定义了一个 Generator function。内部还有三个 yield 。异步
那么上面那段函数是如何执行的呢,一步一步来:异步编程
定义一个 Generator 函数 —— var myGen = function*(){…} ;函数
var gen = myGen() 进行赋值,接下来想要执行函数须要调用 next(),由于 Generator 函数不会本身执行,next() 能够 return 一个对象,包含两个属性,一个是输出的值(yielded value),还有一个是 done property,表示这个 Generator 函数是否已经输出了最后一个值(yielded its last value)了;url
调用 next() 后,执行函数内部第一条语句 var one = yield 1,因为这条函数执行顺序是自右向左,因此先执行 yield 1,yield 1 这里的做用相似 return 1,返回一个 1 ,同时暂停了函数的执行,它后面的语句并不会继续执行下去。因此第一句 console.log(gen.next()) 输出 1。code
以此类推,最后的 console.log(gen.next()) 结果为 {value:undefined,done:true},由于函数已经没有任何 yield,没有 return 任何值回来,done 为 true 表示这个 Generator 函数执行结束了。
myGen 函数内的 console.log(one,two,three) 会输出什么呢? 1,2,3 ?猜错了!其实这里输出的是 undefined,undefined,undefined。由于 yield 在 var one = 和 1 中间,因此 1 并无赋值到变量 one 上面。
下面加一点好玩的东西:把上面全部的 console.log() 改为下面这个样子。
console.log(gen.next()); console.log(gen.next(4)); console.log(gen.next(5)); console.log(gen.next('a'));
这时, console.log(one,two,three) 输出的就是 4,5,a。
WHY?? 刚刚说到 var one = yield 1;的执行顺序是自右向左的,执行到 yield 1就暂停了,因此并无给 one 赋值,因此执行 console.log(gen.next(4)) 语句的时候,把参数 4 赋值给了 one ,而后继续执行 yield 2,以此类推...
然而这看起来好像并无什么卵用?别急,继续往下看 ~
———————————我是分割线—————————————
首先咱们知道日常常常会遇到这样一种状况,就是须要写嵌套的 AJAX,特别是比较复杂的项目里面,AJAX 一层层嵌套( 会存在多层回调嵌套,叫作 Pyramid of Doom),体验很是糟糕。
好比下面这样子的:
$.ajax({ // 第一个AJAX type:'GET', url:'booklist.json', success:function(booklist){ console.log(booklist); $.ajax({ // 第二个AJAX type:'GET', url:'book.json?id='+booklist.id, success:function(book){ console.log(book); $.ajax({ //第三个AJAX type:'GET', url:'comments.json?id='+book[0].id, success:function(comments){ console.log(comments); }, error:function(xhr,status,error){ //处理一些东西 } }); }, error:function(xhr,status,error){ //处理一些东西 } }); }, error:function(xhr,status,error){ //处理一些东西 } })
三个AJAX嵌套在一块儿,虽然被简化了(一些数据处理直接用 console.log() 替代),可是仍是看起来比较乱,一乱起来中午吃个饭回来都找不到上次写到哪里了,然而实际业务中要作的处理也绝对比这多不少。
这里先用一种比较普通的方式来处理上面那大段代码:
$.ajax({ type:'GET', url:'booklist.json', success:getbook, error:handleError }); function getbook(booklist){ console.log(booklist); $.ajax({ type:'GET', url:'book.json?id='+booklist.id, success:getComments, error:handleError }); } function getComments(book){ console.log(book); $.ajax({ type:'GET', url:'comments.json?id='+book[0].id, success:function(comments){ console.log(comments); }, error:handleError }); } function handleError(xhr,status,error){ //处理一些东西 }
上面的代码封装了三个 function,看起来整齐一些了,而且全部的 error 处理都经过调用本身封装好的 handleError 去作,然而咱们的代码量并无减小多少。
下面用 Promise 对代码进行处理:
$.get(booklist.json).then(function(booklist){ console.log(booklist); return $.get('book.json?id='+booklist.id); }).then(function(book){ console.log(book); return $.get('comments.json?id='+book[0].id) }).then(function(comments){ console.log(comments); },handleError); function handleError(xhr,status,error){ //处理一些东西 }
Promise 经过 .then() 将函数串联在一块儿,它采用了同步的方式去处理异步的问题,去除了一层层的回调嵌套,error 处理只须要最后调用一次 handleError 就够了,彷佛已经很好了,不过这里还有更好的方法——Generator。
下面是用 Generator 处理:
Promise.coroutine(function*(){ var booklist = yield $.get('booklist.json'); console.log(booklist); var book = yield $.get('book.json?id='+booklist.id); console.log(book); var comments = yield $.get('comments.json?id='+book[0].id); console.log(book); })().catch(function(errs){ //处理一些东西 })
对比第一段代码,瞬间神清气爽了!Promise.coroutine 是专门用来给 Generator 用的,做用就至关于最开始的那个带上参数的 next()。咱们不须要去把回调函数嵌套在一块儿,或者串联在一块儿就可以获得想要的结果,是否是很是赞~?!!ꉂ ೭(˵¯̴͒ꇴ¯̴͒˵)౨”
References: