首页 > 其他分享 >5分钟带你彻底搞懂async底层实现原理!

5分钟带你彻底搞懂async底层实现原理!

时间:2022-12-15 18:34:44浏览次数:42  
标签:function return 函数 next result async 搞懂 底层

ES2017 标准引入了 async 函数,使得异步操作变得更加方便。

async 函数是什么?一句话,它就是 Generator 函数的语法糖。研究 async 的原理,就必须先弄清楚 Generator 是个啥。

Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同。

形式上,Generator 函数是一个普通函数,但是有两个特征。一是,function关键字与函数名之间有一个星号;二是,函数体内部使用yield表达式,定义不同的内部状态(yield在英语里的意思就是“产出”)

看一个例子:

function* gen(x) {
 var y = yield x + 2;
 return y;
}
​
var g = gen(1);
g.next() // { value: 3, done: false }
g.next() // { value: undefined, done: true }

上面代码中,调用 Generator 函数,会返回一个内部指针(即遍历器)g。这是 Generator 函数不同于普通函数的另一个地方,即执行它不会返回结果,返回的是指针对象。调用指针g的next方法,会移动内部指针(即执行异步任务的第一段),指向第一个遇到的yield语句,上例是执行到x + 2为止。

换言之,next方法的作用是分阶段执行Generator函数。每次调用next方法,会返回一个对象,表示当前阶段的信息(value属性和done属性)。value属性是yield语句后面表达式的值,表示当前阶段的值;done属性是一个布尔值,表示 Generator 函数是否执行完毕,即是否还有下一个阶段。

这样手工的执行next()函数,着实有些麻烦,能写个工具让他自动执行吗?那我们就来试试:

封装一个 spawn 函数,返回一个 spawn 函数,给函数传入 Generator函数作为参数,spawn 实现 next() 方法的执行。

function fn(args) {
 return spawn(function* () {
 // ...
  });
}

spawn 函数的实现:

function spawn(genF) {
 return new Promise(function(resolve, reject) {
 const gen = genF();
 function step(nextF) {
 let next;
 try {
 next = nextF();
      } catch(e) {
 return reject(e);
      }
 if(next.done) {
 return resolve(next.value);
      }
 Promise.resolve(next.value).then(function(v) {
 step(function() { return gen.next(v); });
      }, function(e) {
 step(function() { return gen.throw(e); });
      });
    }
 step(function() { return gen.next(undefined); });
  });
}

应用这个方法执行一下第一个例子:

function fn(x) {
 return spawn(function* gen() {
 var y = yield x + 2
 return y;
  });
}
​
fn(1).then((result) => {
 console.log(result) // 3
})

如果 yield 后面是个 Promise, 就可以实现异步了:

function fn(x) {
 return spawn(function* gen() {
 var y = yield new Promise((resolve) => {
 setTimeout(() => {
 resolve(x + 1)
      }, 1000)
    })
 return y;
  });
}
​
fn(1).then((result) => {
 console.log(result) // 过一秒后打印 3
})

这样,过一秒后就打印 3 了。

从整个代码上来看,实现起来有些麻烦。Async 简化了一切,使用它,不再需要 spawn 函数,只需将 Generator 函数的星号(*)替换成async,将yield替换成await,仅此而已。改造一下:

async function fn(x) {
 let result = await new Promise((resolve) => {
 setTimeout(() => {
 resolve(x + 2)
    }, 1000)
  })
 return result
}
​
fn(1).then((result) => {
 console.log(result)
})

真是简洁了很多。

最后看一个面试题,如何将程序的执行结果 1,3,2,改造为 1,2, 3

<script>
const getUser = () => {
 return new Promise((resolve) => {
 setTimeout(() => {
 resolve(2)
    }, 0)
  })
}
​
export default {
 methods: {
 async onGetUser() {
 getUser().then((result) => {
 console.log(result)
      })
    }
  },
​
 async created() {
 console.log(1)
 await this.onGetUser()
 console.log(3)
  }
}
</script>
​
<template>
 <div>
    hello world
 </div>
</template>
​
<style lang="scss">
 
</style>

只需修改一个 onGetUser 函数即可:

async onGetUser() {
 // getUser().then((result) => {
 //   console.log(result)
 // })
 let result = await getUser()
 console.log(result)
}

以上就是async的原理,你学会了吗?

标签:function,return,函数,next,result,async,搞懂,底层
From: https://www.cnblogs.com/qian-fen/p/16985796.html

相关文章

  • python并发编程之asyncio协程(三)
    协程实现了在单线程下的并发,每一个协程共享线程的几乎全部的资源,除了协程本身私有的上下文栈;协程的切换属于程序级别的切换,对于操做系统来讲是无感知的,所以切换速度更快、......
  • 彻底搞懂JavaScript防抖与节流
    今天为大家带来一篇JS重难点的知识体系,这也是前端高薪必备的重难点知识,而且防抖与节流在各大企业前端面试过程中经常会考到的高频面试题! 为了更好的帮助大家理解防抖......
  • 01-彻底搞懂java的值传递
    01-彻底搞懂java的值传递在java的参数传递中,只有一种情况,就是值传递值传递指的是在方法中,会将原始变量拷贝一份出来,进行处理基本数据类型基本数据类型值就保存在变量......
  • 一文搞懂 Redis 架构演化之路
    作者:ryetan,腾讯CSIG后台开发工程师现如今Redis变得越来越流行,几乎在很多项目中都要被用到,不知道你在使用Redis时,有没有思考过,Redis到底是如何稳定、高性能地提供服务......
  • 究竟是谁负了谁,来自底层测试的2022年终总结
    前言说实话坐在椅子前,都想好了,该怎么去写,甚至感觉有好多要写的,但是当我坐在椅子上时,却不知道该怎么开头了,不知道是不是紧张?还是不舍?难道还没有跟过去挥手告别的勇气吗?当......
  • 究竟是谁负了谁,来自底层测试的2022年终总结
    前言说实话坐在椅子前,都想好了,该怎么去写,甚至感觉有好多要写的,但是当我坐在椅子上时,却不知道该怎么开头了,不知道是不是紧张?还是不舍?难道还没有跟过去挥手告别的勇气吗?当......
  • Java中hashmap底层Hash冲突是什么?以及如何解决Hash冲突 【杭州多测师_王sir】【杭州
    一、hashMap的底层实现hashmap的底层结构在jdk1.7之前是数组+链表,但是在jdk1.8以后,其变成了数组+链表+红黑树,这个操作会加快在链表时候的查询速度。当链表的长度大于8 的......
  • 三、教你搞懂渐变堆叠面积图《手把手教你 ECharts 数据可视化详解》
    注:本系列教程需要对应JavaScript、html、css基础,否则将会导致阅读时困难,本教程将会从ECharts的官方示例出发,详解每一个示例实现,从中学习ECharts。ECharts官方示例:h......
  • 【转载】一步步搞懂MySQL元数据锁(MDL)
    某日,路上收到用户咨询,为了清除空间,想删除某200多G大表数据,且已经确认此表不再有业务访问,于是执行了一条命令‘deletefrombigtable’,但好长时间也没删完,经过咨询后,获知d......
  • 深入理解Whitelabel Error Page底层源码
    深入理解WhitelabelErrorPage底层源码(一)服务器请求处理错误则转发请求urlStandardHostValve的invoke()方法将根据请求的url选择正确的Context来进行处理。在发生错误的......