途牛旅行网网站建设,即将上市的手机,tk免费域名注册,wordpress 查询 分页Generator 函数 1.Generator 函数是 ES6 提供的一种异步编程解决方案#xff0c;语法行为与传统函数完全不同#xff0c;通常有两个特征#xff1a; function关键字与函数名之间有一个星号#xff1b; 函数体内部使用yield表达式#xff0c;定义不同的内部状态 //一个简单… Generator 函数 1.Generator 函数是 ES6 提供的一种异步编程解决方案语法行为与传统函数完全不同通常有两个特征 function关键字与函数名之间有一个星号 函数体内部使用yield表达式定义不同的内部状态 //一个简单的 Generator 函数 function *Generator(){ yield Hello; yield World; return Hello World;
}2.Generator 函数的调用方法与普通函数一样也是在函数名后面加上一对圆括号。不同的是调用 Generator 函数后该函数并不执行返回的也不是函数运行结果而是一个指向内部状态的指针对象,必须调用 next 方法才能使得指针移向下一个状态。也就是说每次调用next方法内部指针就从函数头部或上一次停下来的地方开始执行直到遇到下一个yield表达式或return语句为止。实际上就是Generator 函数是分段执行的yield表达式是暂停执行的标记而next方法可以恢复执行。 function *Generator(){yield Hello;yield World; return Hello World; } let generator Generator(); //无返回 generator.next(); //{value:Hello,done:false} generator.next(); //{value:World,done:false} generator.next(); //{value:Hello World,done:true} generator.next(); //{value:undefined , done:true} 上述代码就是一个 Generator 函数的执行过程 第一次调用 next() 方法 遇到第一个 yield 表达式后返回一个对象对象的 vlaue 属性值是第一个 yield 表达式的值 Hello done属性是 false 表示整个遍历还没有结束第二次调用 next() 方法 Generator 函数从上次yield表达式停下的地方继续执行 遇到第二个 yield 表达式后返回一个对象对象的 vlaue 属性值是第一个 yield 表达式的值 World done属性是 false 表示整个遍历还没有结束第三次调用 next() 方法 Generator 函数从上次yield表达式停下的地方继续执行 一直执行到return语句如果没有return语句就执行到函数结束。此时 next 方法返回的对象的value属性就是 return语句后面的表达式的值如果没有return语句则value属性的值为undefineddone属性的值true表示遍历已经结束第四次调用此时 Generator 函数已经运行完毕next方法返回对象的value属性为undefineddone属性为true。以后再调用next方法返回的都是这个值。3.上述例子中我们可以得知调用 Generator 函数返回一个遍历器对象代表 Generator 函数的内部指针。以后每次调用遍历器对象的next方法就会返回一个有着value和done两个属性的对象。value属性表示当前的内部状态的值是yield表达式或return后面那个表达式的值done属性是一个布尔值表示是否遍历结束。 4.yield 表达式可以看做是Generator 函数的暂停标志要注意的是 yield 表达式后面的表达式只有当调用next方法、内部指针指向该语句时才会执行 function* gen() { yield 123 456; } 上面代码中yield后面的表达式123 456不会立即求值只会在next方法将指针移到这一句时才会求值“惰性求值” 5.yield 表达式与 return 语句都能返回紧跟在语句后面的那个表达式的值不同的是遇到yield函数暂停执行下一次再从该位置继续向后执行而 return 语句不具备位置记忆的功能而且一个函数里面只能执行一个 return 语句但是可以执行多个yield表达式要注意的是 yield 表达式只能用在 Generator 函数里面用在其他地方都会报错。 (function (){yield 1; })() // SyntaxError: Unexpected number 6.Generator 函数可以不用yield表达式这时就变成了一个单纯的暂缓执行函数 function *Generator() { console.log(Hello World) } var generator Generator(); setTimeout(function () { generator.next() }, 2000); // Hello World 7.yield 表达式如果用在另一个表达式之中必须放在圆括号里面如果用作函数参数或放在赋值表达式的右边可以不加括号 function *Generator() { console.log(Hello yield); // SyntaxError console.log(Hello yield 123); // SyntaxError console.log(Hello (yield)); // OK console.log(Hello (yield 123)); // OK } function *Generator() { foo( yield a , yield b ); // OK let input yield; // OK } 8.yield 表达式本身没有返回值或者说是返回 undefined。next 方法可以带一个参数该参数就会被当作上一个 yield 表达式的返回值。 function *Generator() { for(var i 0; true; i) { var reset yield i; if( reset ) { i -1; } } } var g Generator(); g.next() // { value: 0, done: false } g.next() // { value: 1, done: false } g.next(true) // { value: 0, done: false } 上述代码中定义了一个可以无限运行的 Generator 函数如果 next 方法没有参数每次运行到 yield 表达式变量 reset 的值总是 undefined 当 next 方法带一个参数true时变量reset就被重置为这个参数即true因此i会等于-1下一轮循环就会从-1开始递增。 我们利用这个特性在 Generator 函数运行的不同阶段从外部向内部注入不同的值从而调整函数行为 function *foo(x) { var y 2 * (yield (x 1)); var z yield (y / 3); return (x y z); } var a foo(5); a.next() // {value:6, done:false} a.next() // {value:NaN, done:false} a.next() // {value:NaN, done:true} var b foo(5); b.next() // { value:6, done:false } b.next(12) // { value:8, done:false } b.next(13) // { value:42, done:true } 上述代码 a 第二次运行 next 方法的时候不带参数导致 y 的值等于2 * undefined即NaN除以3以后还是NaN因此返回对象的value属性也等于NaN。第三次运行Next方法的时候不带参数所以z等于undefined返回对象的value属性等于5 NaN undefined即NaN; b 调用加了参数结果就不一样了第一次调用next方法时返回 x1 的值 6第二次调用next方法将上一次 yield 表达式的值设为 12 因此 y 等于 24返回 y / 3 的值 8第三次调用next方法将上一次 yield 表达式的值设为 13 因此 z 等于 13 这时 x 等于 5y 等于24所以 return 语句的值等于 42 psnext 方法的参数表示上一个yield表达式的返回值所以在第一次使用next方法时传递参数是无效的 9.for...of循环可以自动遍历 Generator 函数时生成的Iterator对象且此时不再需要调用next方法 function *foo() { yield 1; yield 2; yield 3; yield 4; yield 5; return 6; } for ( let v of foo() ) { console.log(v); } // 1 2 3 4 5 上述代码使用了 for ... of 循环 依次打印了5个 yield 表达式的值此时就不需要 next 方法了但是要注意的是一旦 next 方法的返回对象的 done 属性为 true时for...of循环就会中止且不包含该返回对象因此上面 return 语句返回的 6不包括在for...of循环之中。 10.Generator函数返回的遍历器对象还有一个return方法可以返回给定的值并且终结遍历Generator函数 function *Generator() { yield 1; yield 2; yield 3; } var g Generator(); g.next() // { value: 1, done: false } g.return(ok) // { value: ok, done: true } g.next() // { value: undefined, done: true } 遍历器对象 g 调用 return 方法后返回值的 value 属性就是 return 方法的参数 ok如果 不提供参数则返回值的 value 属性为 undefined 。并且Generator函数的遍历就终止了返回值的 done 属性为 true以后再调用 next 方法value 总是返回 undefined done 属性总是返回 true 11.如果在 Generator 函数内部调用另一个 Generator 函数默认情况下是没有效果的。 function *Generator1() { yield a; yield b; } function *Generator2() { yield x; Generator1(); yield y; } for (let v of Generator2()){ console.log(v); } // x // y 12.可以使用 yield* 表达式用来在一个 Generator 函数里面执行另一个 Generator 函数来达到在 Generator 函数内部调用另一个 Generator 函数的效果 function *Generator1() { yield a; yield b; } function *Generator2() { yield x; yield* Generator1(); yield y; } // 等同于 function *Generator2() { yield x; yield a; yield b; yield y; } // 等同于 function *Generator2() { yield x; for (let v of Generator2()) { yield v; } yield y; } for (let v of Generator2()){ console.log(v); } // x // a // b // y 13.Generator 可以暂停函数执行返回任意表达式的值。这种特点使得 Generator 有多种应用场景; 异步操作的同步化表达 , 可以利用 Generator 函数的暂停执行的效果把异步操作写在 yield 表达式里面等到调用next方法时再往后执行 function *loading() { showLoadingScreen(); yield loadDataAsync(); hideLoadingScreen(); } var loader loading(); // 加载loading loader.next() // 隐藏loadingloader.next()上面代码中第一次调用 loading 函数时该函数不会执行仅返回一个遍历器。下一次对该遍历器调用next方法则会显示Loading界面showLoadingScreen并且异步加载数据loadDataAsync。等到数据加载完成再一次使用next方法则会隐藏Loading界面整个逻辑就很清晰了~ 可以利用 Generator 函数用同步的方式部署 Ajax 操作 function *main(url) { var result yield request( url ); var resp JSON.parse(result); console.log(resp.value); } function request(url) { makeAjaxCall(url, function(response){ it.next(response); }); } var ajax main(); ajax.next(); 上面代码的 main 函数就是通过 Ajax 操作获取数据要注意的是 makeAjaxCall 函数中的 next 方法必须加上 response 参数因为 yield 表达式本身是没有值的总是等于undefined 控制流管理如果有一个多步操作非常耗时采用回调函数可能会写成下面这样 step1(function (value1) {step2(value1, function(value2) { step3(value2, function(value3) { step4(value3, function(value4) { // Do something with value4 }); }); }); }); 如果采用 Promise 写法 Promise.resolve(step1).then(step2).then(step3).then(step4).then(function (value4) { // Do something with value4 }, function (error) { // Handle any error from step1 through step4 }) 采用 Generator 函数来写 function *longRunningTask(value1) { try { var value2 yield step1(value1); var value3 yield step2(value2); var value4 yield step3(value3); var value5 yield step4(value4); // Do something with value4 } catch (e) { // Handle any error from step1 through step4 } } 然后使用一个自动化函数按次序执行所有步骤 scheduler(longRunningTask(initialValue));function scheduler(task) { var taskObj task.next(task.value); // 如果Generator函数未结束就继续调用 if (!taskObj.done) { task.value taskObj.value scheduler(task); } } 14.另外Generator 函数是协程在 ES6 的实现最大特点就是可以交出函数的执行权即暂停执行遇到 yield 命令就暂停等到执行权返回再从暂停的地方继续往后执行另外它的函数体内外的数据交换和错误处理机制的特点使它可以作为异步编程的完整解决方案 转载于:https://www.cnblogs.com/wntd/p/9013316.html