软件开发定制定制ES6+--》熟知JS中的async函数

目录


async函数

async软件开发定制定制函数的返回值为 promise 对象,promise软件开发定制定制对象的结果由async软件开发定制定制函数执行的返回值决定。async软件开发定制定制函数能使得异步操作变软件开发定制定制得更加方便,软件开发定制定制简而言之就是 Generator 的。

定义async函数,软件开发定制定制特点是即便软件开发定制定制函数内部返回结果不是promise对象,调用函数其最后的返回结果依然是promise对象,代码如下:

如果返回的结果不是 Promise 对象的情况下:

  1. <script>
  2. async function fn(){
  3. // 返回的结果是字符串
  4. // return '123'
  5. // // 返回的结果是undefined
  6. // return;
  7. // 返回的结果是抛出一个异常
  8. throw new 'error'
  9. }
  10. const result = fn()
  11. console.log(result);
  12. </script>

如果返回的结果是 Promise 对象时,我们正常使用 then 方法即可,如下:

  1. <script>
  2. async function fn(){
  3. return new Promise((resolve,reject)=>{
  4. // resolve('成功的数据')
  5. reject('失败的数据')
  6. })
  7. }
  8. const result = fn()
  9. // 调用 then 方法
  10. result.then((value)=>{
  11. console.log(value);
  12. },(reason)=>{
  13. console.log(reason); // 打印失败的数据
  14. })
  15. </script>

await 表达式

通过上文的对 async 介绍,感觉其功能有点鸡肋,其实恰恰不是,而是 async 需要搭配 await 一起使用才能达到语法糖的效果。

await的特点

await必须写在 async 函数中

await右侧的表达式一般为 promise 对象

await返回的是 promise 成功的值

await的 promise 失败了,就会抛出异常,需要通过 try...catch捕获处理

说白了:await就相当于 then 方法的第一个回调函数,只返回成功的值,失败的值需要 try...catch来捕获。

async函数内部抛出错误,会导致返回的 Promise 对象变为reject状态。抛出的错误对象会被catch方法回调函数接收到。

  1. <script>
  2. const p = new Promise((resolve,reject)=>{
  3. // resolve('用户数据')
  4. reject('用户加载数据失败了')
  5. })
  6. async function fn(){
  7. // 为防止promise是失败的状态,加上try...catch进行异常捕获
  8. try {
  9. // await 返回的结果就是 promise 返回成功的值
  10. let result = await p
  11. console.log(result);
  12. } catch (error) {
  13. console.log(error);//因为是失败的状态,所以打印:用户加载数据失败了
  14. }
  15. }
  16. fn()
  17. </script>

总结

(1)await命令后面的Promise对象,运行结果可能是rejected,所以最好把await命令放在try...catch代码块中。

(2)如果有多个await命令后面的异步操作,如果不存在继发关系,最好让它们同时触发。

比如:await Promise.all([a(), b()]),这里简单提一下

(3)await命令只能用在async函数之中,如果用在普通函数,就会报错。

(4)(理解一下async的运行原理) async 函数可以保留运行堆栈,普通函数内部运行一个异步任务时,如果异步任务运行结束普通函数可能早就运行完了,异步任务的上下文环境已经消失了,如果异步任务报错,错误堆栈将不包括普通函数;而async函数内部的异步任务运行时,async函数是暂停执行的,所以一旦async函数内部的异步任务运行报错,错误堆栈将包括async函数。

async使用形式

  1. // 函数声明
  2. async function foo() {}
  3. // 函数表达式
  4. const foo = async function () {};
  5. // 对象的方法
  6. let obj = { async foo() {} };
  7. obj.foo().then(...)
  8. // Class 的方法
  9. class Storage {
  10. constructor() {
  11. this.cachePromise = caches.open('avatars');
  12. }
  13. async getAvatar(name) {
  14. const cache = await this.cachePromise;
  15. return cache.match(`/avatars/${name}.jpg`);
  16. }
  17. }
  18. const storage = new Storage();
  19. storage.getAvatar('jake').then(…);
  20. // 箭头函数
  21. const foo = async () => {};

async读取文件

和之前讲解的 一样,我们也可以使用async进行文件的读取,代码如下:

  1. // 1.引入 fs 模块
  2. const fs = require('fs')
  3. // 2.读取文件
  4. function index(){
  5. return new Promise((resolve,reject)=>{
  6. fs.readFile('./index.md',(err,data)=>{
  7. // 如果失败
  8. if(err) reject(err)
  9. // 如果成功
  10. resolve(data)
  11. })
  12. })
  13. }
  14. function index1(){
  15. return new Promise((resolve,reject)=>{
  16. fs.readFile('./index1.md',(err,data)=>{
  17. // 如果失败
  18. if(err) reject(err)
  19. // 如果成功
  20. resolve(data)
  21. })
  22. })
  23. }
  24. function index2(){
  25. return new Promise((resolve,reject)=>{
  26. fs.readFile('./index2.md',(err,data)=>{
  27. // 如果失败
  28. if(err) reject(err)
  29. // 如果成功
  30. resolve(data)
  31. })
  32. })
  33. }
  34. // 3.声明一个 async 函数
  35. async function fn(){
  36. let i = await index()
  37. let i1 = await index1()
  38. let i2 = await index2()
  39. console.log(i.toString());
  40. console.log(i1.toString());
  41. console.log(i2.toString());
  42. }
  43. fn()

async发送AJAX请求

和之前讲解 一样,我们也可以使用async进行发送ajax请求,代码如下:

  1. <script>
  2. // 发送 AJAX请求,返回的结果是 Promise 对象
  3. function sendAjax(url){
  4. return new Promise((resolve,reject)=>{
  5. // 创建对象
  6. const x = new XMLHttpRequest()
  7. // 初始化
  8. x.open('GET',url)
  9. // 发送
  10. x.send()
  11. // 事件绑定
  12. x.onreadystatechange = function(){
  13. if(x.readyState === 4){
  14. if(x.status >= 200 && x.status < 300){
  15. // 如果响应成功
  16. resolve(x.response)
  17. // 如果响应失败
  18. reject(x.status)
  19. }
  20. }
  21. }
  22. })
  23. }
  24. // promise then 方法测试
  25. // const result = sendAjax("https://ai.baidu.com/").then(value=>{
  26. // console.log(value);
  27. // },reason=>{})
  28. // async 与 await 测试
  29. async function fn(){
  30. // 发送 AJAX 请求
  31. let result = await sendAjax("https://ai.baidu.com/")
  32. console.log(result);
  33. }
  34. fn()
  35. </script>

与生成器(Generator)相比

我们发现 async与await之间的关系 和 Generator与yield之间的关系十分类似,不熟悉Generator的朋友可以看一下我之前的文章: ;一比较就发现: async函数就是将 Generator 函数的星号(*)替换成async,将yield替换成await。代码比较如下:

  1. <script>
  2. // Generator 函数
  3. function * person() {
  4. console.log('hello world');
  5. yield '第一分隔线'
  6. console.log('hello world 1');
  7. yield '第二分隔线'
  8. console.log('hello world 2');
  9. yield '第三分隔线'
  10. }
  11. let iterator = person()
  12. // console.log(iterator); 打印的就是一个迭代器对象,里面有一个 next() 方法,我们借助next方法让它运行
  13. iterator.next()
  14. iterator.next()
  15. iterator.next()
  16. // async函数
  17. const person1 = async function (){
  18. console.log('hello world');
  19. await '第一分隔线'
  20. console.log('hello world 1');
  21. await '第二分隔线'
  22. console.log('hello world 2');
  23. await '第三分隔线'
  24. }
  25. person1()
  26. </script>

async函数的实现原理就是将 Generator 函数和自动执行器包装在一个函数里。

  1. <script>
  2. async function fn(args) {}
  3. // 等同于
  4. function fn(args) {
  5. // spawn函数就是自动执行器
  6. return spawn(function* () {});
  7. }
  8. </script>

我们可以分析一下 Generator 和 async 代码的书写特点和风格:

  1. <script>
  2. // Generator 函数
  3. function Generator(a, b) {
  4. return spawn(function*() {
  5. let r = null;
  6. try {
  7. for(let k of b) {
  8. r = yield k(a);
  9. }
  10. } catch(e) {
  11. /* 忽略错误,继续执行 */
  12. }
  13. return r;
  14. });
  15. }
  16. // async 函数
  17. async function async(a, b) {
  18. let r = null;
  19. try {
  20. for(let k of b) {
  21. r = await k(a);
  22. }
  23. } catch(e) {
  24. /* 忽略错误,继续执行 */
  25. }
  26. return r;
  27. }
  28. </script>

所以 async 函数的实现符合语义也很简洁,不用写Generator的自动执行器,改在语言底层提供,因此代码量少。 

从上文代码我们可以总结以下几点

(1)执行需要借助执行器,而async函数自带执行器,即async不需要像生成器一样需要借助 next 方法才能执行,而是会自动执行。

(2)相比于生成器函数,我们可以看到 async 函数的语义更加清晰

(3)上面就说了,async函数可以接受Promise或者其他原始类型,而生成器函数yield命令后面只能是Promise对象或者Thunk函数。

(4)async函数返回值只能是Promise对象,而生成器函数返回值是 Iterator 对象

网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发