手写Generator实现async函数

第一步

实现一个手写的genator 函数

/**
			 * 第一步
			 * @description  实现一个手写的genator 函数
			 * */
			// 测试的generator函数
			function* test() {
				var a = 1;
				yield a;
				let b = 2;
				return a
			}
			// babel 对 generator code split(草鞋版)
			function splitIterator(fx) {
				let code = fx.toString().match(/{(.|\s)*}/g)[0].slice(1, -1);
				// 从代码中提取变量,变量提升
				let variable = code.match(/let(\s*).|var(\s*).|const(\s*).*/g).join(";");
				// 移除主体代码中的变量声明
				let rmCodeVeriable = code.replace(/let|var|const/g, '');
				// 替换yield为return,按照yield切片
				let mainCode = rmCodeVeriable.match(/(.|\s)*?(yield|return).*/g).map(v => v.replace(/yield/g, "return"))
				// yield切片实际执行代码
				const codeTranslate = mainCode.map((v, i) => {
					return `
						case ${i}:
							context.next = ${i+1}
							context.done = ${i+1 >= mainCode.length ? 'true' : 'false'}
							${
								v
								// replace(/(.+\s*=*\s*)(yield|return)(\s*.*)/g,`$2$3$1p`)
							}
					`
				})
				// next方法实际执行函数
				const excuteFx = `
					var fx = function (){
						while(1){
								switch(context.per = context.next){
									${codeTranslate.join("")}
									default:
										context.done = true
										context.value = undefined
										return;
								}
						}
					}
				`
				return {
					variable,
					excuteFx
				}
			}
			// console.log(splitIterator(test))
			function Generator(test, fxString) {
				// 转换Generator函数为ES3
				const {
					variable,
					excuteFx
				} = splitIterator(test)
				// 上下文环境
				const context = {
					per: 0,
					next: 0,
					done: false,
					value: undefined
				}
				// 进行变量提升
				eval(variable)
				// 声明next函数实际执行函数
				eval(fxString || excuteFx)
				// 迭代器
				return {
					next: function(paramters) {
						return {
							value: fx(paramters),
							done: context.done,
						}
					}
				}
			}
			
			var a = Generator(test)
			console.log(a.next())
			console.log(a.next())
			console.log(a.next())

第二步

使用generator手写一个代替async&await函数可的函数

/**
			 * 第二步
			 * @description 使用generator手写一个代替async&await函数可的函数
			 * */
			async function testTemple() {
				var content = await fetch("https://juejin.cn/post/6844903929369591822");
				console.log(await content.text())
				return content
			}

			function executeAsyncFX(iterator) {
				var gen = iterator || (function* asyncFxAsGenator() {
					var content = yield fetch(
						"http://127.0.0.1:8848/note/%E5%89%8D%E7%AB%AF/%E6%89%8B%E5%86%99/Generator.html");
					console.log("2222")
					console.log(yield content.text())
					return content
				})(); // 将async函数testTemple转化成一个 generator函数

				(function(value) { //不能使用箭头函数,因为这样arguments.callee指向会执行上级
					const results = gen.next(value);
					// console.log(results)
					Promise.resolve(results.value).then(
						(v) => {
							// console.log(v)
							if (!results.done) {

								console.log(v)
								arguments.callee(v)
							}
						}
					);
				})() // 让这个iterator自执行知道完成,遇到返回promise 也就是 awaite后面的表达式保证执行完成,并将结果传入下一次执行
			}

		executeAsyncFX()

第三步

使用第一步中手写的generator 代替第二步中的 generator

/**
			 * 第三步
			 * @description 使用第一步中手写的generator 代替第二步中的 generator
			 * */
			var gen = function* asyncFxAsGenator() {
				var content = yield fetch("http://127.0.0.1:8848/note/%E5%89%8D%E7%AB%AF/%E6%89%8B%E5%86%99/Generator.html");
				console.log("2222")
				console.log(yield content.text())

				return content
			}
			// 上面的代码分割函数转化不了,手动改了下
			var iterator = Generator(gen, `var fx = function (paramters){
										while(1){
												switch(context.per = context.next){
													
										case 0:
											context.next = 1
											context.done = false
									    return fetch("http://127.0.0.1:8848/note/%E5%89%8D%E7%AB%AF/%E6%89%8B%E5%86%99/Generator.html");
									
										case 1:
										  content = paramters
											context.next = 2
											context.done = false
											
											console.log("2222")
											return content.text()
									
										case 2:
											context.next = 3
											context.done = true
									    return content
									
													default:
														context.done = true
														context.value = undefined
														return;
												}
										}
									}`)

			executeAsyncFX(iterator)

总结:aync函数手写实现

  • 可以通过一个自动执行的generator实现,实际内部也依靠Promise.resolve,then 回调函数递归实现。
  • 也可以通过babel直接将await后面表达式转成Promise.resolve在then回调里面执行余下直到下一个await的代码,也就是回调地域。
  • 也就是说async的实现实际上依赖的是promise。
上一篇:阿里首席技术官程立:“双十一”的技术挑战进入新的历史阶段


下一篇:标记(TAG)您的阿里云ECS资源