网站建设挣钱 知乎,移动网站建站系统下载,西宁网站建设报价壹君博贴心,河南百度建个网站从C#到TypeScript - Generator 上篇讲了Promise#xff0c;Promise的执行需要不停的调用then#xff0c;虽然比callback要好些#xff0c;但也显得累赘。所以ES6里添加了Generator来做流程控制#xff0c;可以更直观的执行Promise#xff0c;但终级方案还是ES7议案中的asy…从C#到TypeScript - Generator 上篇讲了PromisePromise的执行需要不停的调用then虽然比callback要好些但也显得累赘。所以ES6里添加了Generator来做流程控制可以更直观的执行Promise但终级方案还是ES7议案中的async await。当然async await本质上也还是Generator可以算是Generator的语法糖。所以这篇先来看下Generator. Generator语法 先来看个例子 function* getAsync(id: string){ yield id; yield id; return finish; } let p getAsync(123); console.info(p.next()); console.info(p.next()); console.info(p.next()); 先看下和普通函数的区别function后面多了一个*变成了function*函数体用到了yield这个大家比较熟悉C#也有返回可枚举集合有时会用到。在ES6里yield同样表示返回一个迭代器所以用到的时候会用next()来顺序执行返回的迭代器函数。上面代码返回的结果如下 { value: id, done: false } { value: 123, done: false } { value: finish, done: true } 可以看到next()的结果是一个对象value表示yield的结果done表示是否真正执行完。所以看到最后return了finish时done就变成true了如果这时再继续执行next()得到的结果是{ value: undefined, done: true }. Generator原理和使用 Generator其实是ES6对协程的一种实现即在函数执行过程中允许保存上下文同时暂停执行当前函数转而去执行其他代码过段时间后达到条件时继续以上下文执行函数后面内容。所谓协程其实可以看做是比线程更小的执行单位一个线程可以有多个协程协程也会有自己的调用栈不过一个线程里同一时间只能有一个协程在执行。而且线程是资源抢占式的而协程则是合作式的怎样执行是由协程自己决定。由于JavaScript是单线程语言本身就是一个不停循环的执行器所以它的协程是比较简单的线程和协程关系是 1:N。同样是基于协程goroutine的go语言实现的是 M:N要同时协调多个线程和协程复杂得多。在Generator中碰到yield时会暂停执行后面代码碰到有next()时再继续执行下面部分。 当函数符合Generator语法时直接执行时返回的不是一个确切的结果而是一个函数迭代器因此也可以用for...of来遍历遍历时碰到结果done为true则停止。 function* getAsync(id: string){ yield id; yield id; return finish; } let p getAsync(123); for(let id of p){ console.info(id); } 打印的结果是 id
123 因为最后一个finish的done是true所以for...of停止遍历最后一个就不会打印出来。另外Generator的next()是可以带参数的 function* calc(num: number){ let count yield 1 num; return count 1; } let p calc(2); console.info(p.next().value); // 3 console.info(p.next().value); // NaN //console.info(p.next(3).value); // 4 上面的代码第一个输出是yield 1 num的结果yield 1返回1加上传进来的2结果是3.继续输出第二个按正常想法应该输出3但是由于yield 1是上一轮计算的这轮碰到上一轮的yield时返回的总是undefined。这就导致yield 1返回undefinedundefined num返回的是NaNcount 1也还是NaN所以输出是NaN。注释掉第二个使用第三个就可以返回预期的值第三个把上一次的结果3用next(3)传进去所以可以得到正确结果。如果想一次调用所有可以用这次方式来递归调用 let curr p.next();
while(!curr.done){console.info(curr.value);curr p.next(curr.value);
}
console.info(curr.value); // 最终结果 Generator可以配合Promise来更直观的完成异步操作。 function delay(): Promisevoid{ return new Promisevoid((resolve, reject){setTimeout(()resolve(), 2000)}); } function* run(){ console.info(start); yield delay(); console.info(finish); } let generator run(); generator.next().value.then(()generator.next()); 就run这个函数来看从上到下执行是很好理解的先输出start等待2秒再输出finish。只是执行时需要不停的使用then好在TJ大神写了CO模块可以方便的执行这种函数把Generator函数传给co即可。 co(run).then(()console.info(success)); co的实现原理可以看下它的核心代码 function co(gen) { var ctx this; var args slice.call(arguments, 1); return new Promise(function(resolve, reject) { if (typeof gen function) gen gen.apply(ctx, args); if (!gen || typeof gen.next ! function) return resolve(gen); onFulfilled(); //最主要就是这个函数递归执行next()和then() function onFulfilled(res) { var ret; try { ret gen.next(res); // next(), res是上一轮的结果 } catch (e) { return reject(e); } next(ret); // 里面调用then并再次调用onFulfilled()实现递归 return null; } function onRejected(err) { // 处理失败的情况 var ret; try { ret gen.throw(err); } catch (e) { return reject(e); } next(ret); } function next(ret) { if (ret.done) return resolve(ret.value); // done是true的话表示完成结束递归 var value toPromise.call(ctx, ret.value); if (value isPromise(value)) return value.then(onFulfilled, onRejected); //递归onFulfilled return onRejected(new TypeError(You may only yield a function, promise, generator, array, or object, but the following object was passed: String(ret.value) )); } }); } 可以看到co的核心代码和我上面写的递归调用Generator函数的本质是一样的不断调用下一个Promise直到done为true。 纵使有co这个库但是使用起来还是略有不爽下篇就轮到async await出场前面这两篇都是为了更好的理解下一篇。转载于:https://www.cnblogs.com/yulei126/p/6790030.html