一、Generator的基本概念1.定义Gernerator函数Generator是一种函数这种函数是ES6提出的一种异步编程的解决方案在它内部使用yield关键字封装了一个个状态机。这个函数的执行结果就是一个遍历器对象。function*next(){yield1;yield22;return3;}varfunnext();console.log(fun.next());//{value: 1, done: false}console.log(fun.next());//{value: 4, done: false}console.log(fun.next());//{value: 3, done: true}console.log(fun.next());//{value: undefined, done: true}Generator函数返回的是一个遍历器对象这个遍历器对象拥有next方法调用这个方法就能得到yield关键字标识状态的结果。2.Generator函数特征function 关键字和函数之间有一个星号(*),且内部使用yield表达式定义不同的内部状态调用Generator函数后该函数并不执行返回的也不是函数运行结果而是一个指向内部状态的指针对象Generator 函数是分段执行的yield表达式是暂停执行的标记而next方法可以恢复执行3.异步编程所谓异步简单说就是一个任务分成两段先执行第一段然后转而执行其他任务等做好了准备再回过头执行第二段。异步编程方式回调函数事件监听发布/订阅者Promise对象所谓回调函数就是把第二段单独写在一个函数里面等到重新执行这个任务的时候就直接调用这个函数。回调函数的异步方式容易形成多重嵌套多个异步操作形成了强耦合只要有一个操作需要修改它的上层回调函数和下层回调函数可能都要跟着修改。这种情况就称为”回调函数地狱”callback hell。Promise可以解决callback hell问题Promise对象允许回调函数的嵌套改成链式调用。Generator函数之所以是一种完美的异步编程解决方案本质上是因为它的两个特点函数体内外的数据交换和完美的错误处理机制。二、yield 表达式Generator 函数返回的遍历器对象只有调用 next 方法才会遍历下一个内部状态所以其实提供了一种可以暂停执行的函数。1.yield 表达式就是暂停标志yield 表达式后面的表达式只有当调用next方法、内部指针指向该语句时才会执行2.使用yield需注意yield语句只能用于function*的作用域如果function*的内部还定义了其他的普通函数则函数内部不允许使用yield语句yield语句如果参与运算必须用括号括起来三、next() 方法1.next 方法参数表示上一个yield表达式的返回值所以在第一次使用next方法时传递参数是无效的。V8 引擎直接忽略第一次使用next方法时的参数只有从第二次使用next方法开始参数才是有效的。从语义上讲第一个next方法用来启动遍历器对象所以不用带有参数。2.遍历器对象的 next 方法的运行逻辑遇到yield表达式就暂停执行后面的操作并将紧跟在yield后面的那个表达式的值作为返回的对象的value属性值。下一次调用next方法时再继续往下执行直到遇到下一个yield表达式。如果没有再遇到新的yield表达式就一直运行到函数结束直到return语句为止并将return语句后面的表达式的值作为返回的对象的value属性值。如果该函数没有return语句则返回的对象的value属性值为undefined。3.return 方法跟 next 方法的区别return终结遍历之后的yield语句都失效next返回本次yield语句的返回值。return没有参数的时候返回{ value: undefined, done: true }next没有参数的时候返回本次yield语句的返回值。return有参数的时候覆盖本次yield语句的返回值也就是说返回{ value: 参数, done: true }next有参数的时候覆盖上次yield语句的返回值返回值可能跟参数有关参数参与计算的话也可能跟参数无关参数不参与计算。4.for…of 循环可以自动遍历Generator函数时生成的Iterator对象且此时不再需要调用next方法。一旦next方法的返回对象的done属性为truefor…of循环就会中止且不包含该返回对象。5.示例next()方法// 定义一个Generator函数function*foo(x){vary2*(yield(x1));varzyield(y/3);return(xyz);}varafoo(5);console.log(a.next());// Object{value:6, done:false} 第一次调用a的next方法时返回x1的值6console.log(a.next());// Object{value:NaN, done:false} 第二次运行next方法的时候不带参数导致y的值等于2 * undefined即NaN除以3以后还是NaNconsole.log(a.next());// Object{value:NaN, done:true} 第三次运行Next方法的时候不带参数所以z等于undefined返回对象的value属性等于5 NaN undefined即NaN。varbfoo(5);console.log(b.next());// {value:6, done:false } 第一次调用b的next方法时返回x1的值6console.log(b.next(12));// {value:8, done:false } 第二次调用next方法将上一次yield表达式的值设为12因此y等于24返回y / 3的值8console.log(b.next(13));// {value:42, done:true } 第三次调用next方法将上一次yield表达式的值设为13因此z等于13这时x等于5y等于24所以return语句的值等于42。Genarator 部署Ajax操作function*main(){// 通过 Ajax 操作获取数据varresultyieldrequest(http://some.url);varresJSON.parse(result);console.log(res.value);}functionrequest(url){makeAjaxCall(url,function(res){it.next(res);})}varitmain();console.log(it.next());Genarator 对任意对象部署 Iterator 接口function*deployObjectInterface(obj){letkeysObject.keys(obj);for(leti0;ikeys.length;i){letkeykeys[i];yield[key,obj[key]];}}letobj{name:Cynthia,age:21};for(let[key,value]ofdeployObjectInterface(obj)){console.log(key,value);}// name Cynthia// age 21Genarator 对数组部署 Iterator 接口function*deployArrayInterface(arr){varnextIndex0;while(nextIndexarr.length){yieldarr[nextIndex];}}vararrdeployArrayInterface([name,age]);console.log(arr.next());// {value: name, done: false}console.log(arr.next().value);// nameconsole.log(arr.next().done);// falseconsole.log(arr.next().value);// ageconsole.log(arr.next().done);// trueconsole.log(arr.next().value);// undefinedconsole.log(arr.next().done);// true
Generator函数
一、Generator的基本概念1.定义Gernerator函数Generator是一种函数这种函数是ES6提出的一种异步编程的解决方案在它内部使用yield关键字封装了一个个状态机。这个函数的执行结果就是一个遍历器对象。function*next(){yield1;yield22;return3;}varfunnext();console.log(fun.next());//{value: 1, done: false}console.log(fun.next());//{value: 4, done: false}console.log(fun.next());//{value: 3, done: true}console.log(fun.next());//{value: undefined, done: true}Generator函数返回的是一个遍历器对象这个遍历器对象拥有next方法调用这个方法就能得到yield关键字标识状态的结果。2.Generator函数特征function 关键字和函数之间有一个星号(*),且内部使用yield表达式定义不同的内部状态调用Generator函数后该函数并不执行返回的也不是函数运行结果而是一个指向内部状态的指针对象Generator 函数是分段执行的yield表达式是暂停执行的标记而next方法可以恢复执行3.异步编程所谓异步简单说就是一个任务分成两段先执行第一段然后转而执行其他任务等做好了准备再回过头执行第二段。异步编程方式回调函数事件监听发布/订阅者Promise对象所谓回调函数就是把第二段单独写在一个函数里面等到重新执行这个任务的时候就直接调用这个函数。回调函数的异步方式容易形成多重嵌套多个异步操作形成了强耦合只要有一个操作需要修改它的上层回调函数和下层回调函数可能都要跟着修改。这种情况就称为”回调函数地狱”callback hell。Promise可以解决callback hell问题Promise对象允许回调函数的嵌套改成链式调用。Generator函数之所以是一种完美的异步编程解决方案本质上是因为它的两个特点函数体内外的数据交换和完美的错误处理机制。二、yield 表达式Generator 函数返回的遍历器对象只有调用 next 方法才会遍历下一个内部状态所以其实提供了一种可以暂停执行的函数。1.yield 表达式就是暂停标志yield 表达式后面的表达式只有当调用next方法、内部指针指向该语句时才会执行2.使用yield需注意yield语句只能用于function*的作用域如果function*的内部还定义了其他的普通函数则函数内部不允许使用yield语句yield语句如果参与运算必须用括号括起来三、next() 方法1.next 方法参数表示上一个yield表达式的返回值所以在第一次使用next方法时传递参数是无效的。V8 引擎直接忽略第一次使用next方法时的参数只有从第二次使用next方法开始参数才是有效的。从语义上讲第一个next方法用来启动遍历器对象所以不用带有参数。2.遍历器对象的 next 方法的运行逻辑遇到yield表达式就暂停执行后面的操作并将紧跟在yield后面的那个表达式的值作为返回的对象的value属性值。下一次调用next方法时再继续往下执行直到遇到下一个yield表达式。如果没有再遇到新的yield表达式就一直运行到函数结束直到return语句为止并将return语句后面的表达式的值作为返回的对象的value属性值。如果该函数没有return语句则返回的对象的value属性值为undefined。3.return 方法跟 next 方法的区别return终结遍历之后的yield语句都失效next返回本次yield语句的返回值。return没有参数的时候返回{ value: undefined, done: true }next没有参数的时候返回本次yield语句的返回值。return有参数的时候覆盖本次yield语句的返回值也就是说返回{ value: 参数, done: true }next有参数的时候覆盖上次yield语句的返回值返回值可能跟参数有关参数参与计算的话也可能跟参数无关参数不参与计算。4.for…of 循环可以自动遍历Generator函数时生成的Iterator对象且此时不再需要调用next方法。一旦next方法的返回对象的done属性为truefor…of循环就会中止且不包含该返回对象。5.示例next()方法// 定义一个Generator函数function*foo(x){vary2*(yield(x1));varzyield(y/3);return(xyz);}varafoo(5);console.log(a.next());// Object{value:6, done:false} 第一次调用a的next方法时返回x1的值6console.log(a.next());// Object{value:NaN, done:false} 第二次运行next方法的时候不带参数导致y的值等于2 * undefined即NaN除以3以后还是NaNconsole.log(a.next());// Object{value:NaN, done:true} 第三次运行Next方法的时候不带参数所以z等于undefined返回对象的value属性等于5 NaN undefined即NaN。varbfoo(5);console.log(b.next());// {value:6, done:false } 第一次调用b的next方法时返回x1的值6console.log(b.next(12));// {value:8, done:false } 第二次调用next方法将上一次yield表达式的值设为12因此y等于24返回y / 3的值8console.log(b.next(13));// {value:42, done:true } 第三次调用next方法将上一次yield表达式的值设为13因此z等于13这时x等于5y等于24所以return语句的值等于42。Genarator 部署Ajax操作function*main(){// 通过 Ajax 操作获取数据varresultyieldrequest(http://some.url);varresJSON.parse(result);console.log(res.value);}functionrequest(url){makeAjaxCall(url,function(res){it.next(res);})}varitmain();console.log(it.next());Genarator 对任意对象部署 Iterator 接口function*deployObjectInterface(obj){letkeysObject.keys(obj);for(leti0;ikeys.length;i){letkeykeys[i];yield[key,obj[key]];}}letobj{name:Cynthia,age:21};for(let[key,value]ofdeployObjectInterface(obj)){console.log(key,value);}// name Cynthia// age 21Genarator 对数组部署 Iterator 接口function*deployArrayInterface(arr){varnextIndex0;while(nextIndexarr.length){yieldarr[nextIndex];}}vararrdeployArrayInterface([name,age]);console.log(arr.next());// {value: name, done: false}console.log(arr.next().value);// nameconsole.log(arr.next().done);// falseconsole.log(arr.next().value);// ageconsole.log(arr.next().done);// trueconsole.log(arr.next().value);// undefinedconsole.log(arr.next().done);// true