全国旗舰校区

不同学习城市 同样授课品质

北京

深圳

上海

广州

郑州

大连

武汉

成都

西安

杭州

青岛

重庆

长沙

哈尔滨

南京

太原

沈阳

合肥

贵阳

济南

下一个校区
就在你家门口
+
当前位置:首页  >  技术干货  >  详情

web前端之async的原理

来源:千锋教育
发布人:qyf
2023-03-03

推荐

在线提问>>

web前端之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)

  }

相关文章

软件性能测试主要看什么指标?

JVM如何实现跨平台呢

5秒完播率是什么意思?

nginx是什么?有哪些优点?

jquery中如何触发事件?

开班信息 更多>>

课程名称
全部学科
咨询

HTML5大前端

Java分布式开发

Python数据分析

Linux运维+云计算

全栈软件测试

大数据+数据智能

智能物联网+嵌入式

网络安全

全链路UI/UE设计

Unity游戏开发

新媒体短视频直播电商

影视剪辑包装

游戏原画

    在线咨询 免费试学 教程领取