iis服务器助手广告广告
返回顶部
首页 > 资讯 > 前端开发 > 其他 >深入探讨JavaScript中的async函数
  • 828
分享到

深入探讨JavaScript中的async函数

asyncawaitjavascript 2022-11-22 23:11:44 828人浏览 安东尼
摘要

说白了:await就相当于 then 方法的第一个回调函数,只返回成功的值,失败的值需要 try...catch来捕获。async函数内部抛出错误,会导致返回的 Promise 对象变为reject状态。抛出的错误对象会被catch方法回调

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

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

<script>
    const p = new Promise((resolve,reject)=>{
        // resolve('用户数据')
        reject('用户加载数据失败了')
    })
    async function fn(){
        // 为防止promise是失败的状态,加上try...catch进行异常捕获
        try {
            // await 返回的结果就是 promise 返回成功的值
            let result = await p
            console.log(result);
        } catch (error) {
            console.log(error);//因为是失败的状态,所以打印:用户加载数据失败了
        }
    }
    fn()
</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使用形式

// 函数声明
async function foo() {}
 
// 函数表达式
const foo = async function () {};
 
// 对象的方法
let obj = { async foo() {} };
obj.foo().then(...)
 
// Class 的方法
class Storage {
  constructor() {
    this.cachePromise = caches.open('avatars');
  }
 
  async getAvatar(name) {
    const cache = await this.cachePromise;
    return cache.match(`/avatars/${name}.jpg`);
  }
}
 
const storage = new Storage();
storage.getAvatar('jake').then(…);
 
// 箭头函数
const foo = async () => {};

async读取文件

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

// 1.引入 fs 模块
const fs = require('fs')
 
// 2.读取文件
function index(){
    return new Promise((resolve,reject)=>{
        fs.readFile('./index.md',(err,data)=>{
            // 如果失败
            if(err) reject(err)
            // 如果成功
            resolve(data)
        })
    })
}
function index1(){
    return new Promise((resolve,reject)=>{
        fs.readFile('./index1.md',(err,data)=>{
            // 如果失败
            if(err) reject(err)
            // 如果成功
            resolve(data)
        })
    })
}
function index2(){
    return new Promise((resolve,reject)=>{
        fs.readFile('./index2.md',(err,data)=>{
            // 如果失败
            if(err) reject(err)
            // 如果成功
            resolve(data)
        })
    })
}
 
// 3.声明一个 async 函数
async function fn(){
    let i = await index()
    let i1 = await index1()
    let i2 = await index2()
    console.log(i.toString());
    console.log(i1.toString());
    console.log(i2.toString());
}
fn()

async发送AJAX请求

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

<script>
    // 发送 AJAX请求,返回的结果是 Promise 对象
    function sendAjax(url){
        return new Promise((resolve,reject)=>{
            // 创建对象
            const x = new XMLHttpRequest()
 
            // 初始化
            x.open('GET',url)
 
            // 发送
            x.send()
 
            // 事件绑定
            x.onreadystatechange = function(){
                if(x.readyState === 4){
                    if(x.status >= 200 && x.status < 300){
                        // 如果响应成功
                        resolve(x.response)
                        // 如果响应失败
                        reject(x.status)
                    }
                }
            }
        })
    }
        
    // promise then 方法测试
    // const result = sendAjax("https://ai.baidu.com/").then(value=>{
    //     console.log(value);
    // },reason=>{})
    // async 与 await 测试
    async function fn(){
        // 发送 AJAX 请求
        let result = await sendAjax("https://ai.baidu.com/")
        console.log(result);
    }
    fn()
</script>

与生成器(Generator)相比

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

<script>
    // Generator 函数
    function * person() {
        console.log('hello world');
        yield '第一分隔线' 
    
        console.log('hello world 1');
        yield '第二分隔线'
    
        console.log('hello world 2');
        yield '第三分隔线'
    }
    let iterator = person()
    // console.log(iterator); 打印的就是一个迭代器对象,里面有一个 next() 方法,我们借助next方法让它运行
    iterator.next()
    iterator.next()
    iterator.next()
 
    // async函数
    const person1 = async function (){
        console.log('hello world');
        await '第一分隔线' 
    
        console.log('hello world 1');
        await '第二分隔线'
    
        console.log('hello world 2');
        await '第三分隔线'
    }
    person1()
</script>

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

<script>
    async function fn(args) {}
    // 等同于
    function fn(args) {
        // spawn函数就是自动执行器
        return spawn(function* () {});
    }
</script>

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

<script>
    // Generator 函数
    function Generator(a, b) {
        return spawn(function*() {
            let r = null;
            try {
                for(let k of b) {
                r = yield k(a);
                }
            } catch(e) {
                
            }
            return r;
        });
    }
 
    // async 函数
    async function async(a, b) {
        let r = null;
        try {
            for(let k of b) {
            r = await k(a);
            }
        } catch(e) {
         
        }
        return r;
    }
</script>

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

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

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

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

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

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

【推荐学习javascript高级教程

以上就是深入探讨JavaScript中的async函数的详细内容,更多请关注编程网其它相关文章!

--结束END--

本文标题: 深入探讨JavaScript中的async函数

本文链接: https://www.lsjlt.com/news/173464.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 深入探讨JavaScript中的async函数
    说白了:await就相当于 then 方法的第一个回调函数,只返回成功的值,失败的值需要 try...catch来捕获。async函数内部抛出错误,会导致返回的 Promise 对象变为reject状态。抛出的错误对象会被catch方法回调...
    99+
    2022-11-22
    async await javascript
  • 深入浅出探究JavaScript中的async与await
    目录1、前言2、详解2.1、async2.1.1、函数返回非Promise对象2.1.2、函数返回Promise对象2.2、await2.3、async、await结合使用2.4、a...
    99+
    2024-04-02
  • golang函数的优缺点深入探讨
    go 函数的优点包括重用性、封装性、可测试性、代码灵活性、并行性。缺点包括性能开销、可读性、可维护性、命名冲突、内存占用量。利用函数时,权衡优点和缺点至关重要,以提高代码质量和可维护性。...
    99+
    2024-04-19
    函数 golang 内存占用 封装性
  • 深入探讨JavaScript中的内存管理
    内存管理是编程语言的基本能力,JavaScript 中的内存管理是通过 V8 完成的。V8 的实现遵循 ECMA-262 规范,而规范中没有阐述内存布局以及内存管理相关信息,所以它的原理取决于解释器的实现。唯一肯定的是不管任何编程语言,内存...
    99+
    2023-05-14
    前端 JavaScript
  • 深入探讨JavaScript用作什么
    随着计算机和互联网的发展,编程已成为一项非常重要的技能。JavaScript作为一种广泛使用的编程语言,被广泛应用于各种网站和应用程序中。本文将深入探讨JavaScript用作什么,并探讨它的一些关键特性和功能。网页交互JavaScript...
    99+
    2023-05-14
  • 深入探讨PHP中rand函数的随机性问题
    标题:深入探讨PHP中rand函数的随机性问题 在编程中,随机数的生成是一项经常会用到的功能之一。在PHP编程中,我们通常会使用rand()函数来生成一个随机数。然而,对于rand()...
    99+
    2024-03-12
    php rand函数 随机性
  • 深入探讨PHP isset()函数的各种用法
    在PHP中,isset()函数是一个非常常用的函数,该函数用于检查变量是否设置并且非NULL。该函数可以用于检查变量、数组成员、对象属性是否被设置。在本文中,我们将深入探讨isset()函数的各种用法。基本用法最常用的形式是检查单个变量。例...
    99+
    2023-05-14
    php
  • 深入探讨Go语言函数的使用案例
    珍惜时间,勤奋学习!今天给大家带来《深入探讨Go语言函数的使用案例》,正文内容主要涉及到等等,如果你正在学习Golang,或者是对Golang有疑问,欢迎大家关注我!后面我会持续更新相关内容的,希望...
    99+
    2024-04-04
  • 深入探讨Go语言函数的应用场景
    Go语言是一种现代化、简洁且高效的编程语言,由Google开发并在开源社区中得到广泛应用。在Go语言中,函数是一个基本的代码块,具有独立性且可以重复调用,对于实现代码的模块化和结构化具...
    99+
    2024-04-02
  • 深入探讨Vue 3中的组合式函数编程方式
    目录什么是组合式函数​鼠标跟踪器示例​异步状态示例​约定和最佳实践​ 命名​输入参数​返回值​副作用​使用限制​通过抽取组合式函数改善代码结构选项式API中使用组合式函数​与其他模式...
    99+
    2023-05-18
    Vue组合式函数 Vue组合式编程
  • 深入探讨:Go语言主函数的等待机制
    标题:深入探讨:Go语言主函数的等待机制 Go语言作为一门高效、并发性强的编程语言,其特有的主函数等待机制在编写多线程程序时显得尤为重要。本文将深入探讨Go语言中主函数的等待机制,结合...
    99+
    2024-03-11
    go语言 主函数 等待机制
  • 深入探讨Golang中的数据处理方法
    深入探讨Golang中的数据处理方法导言:在当今的信息时代,数据是无处不在的。对于开发者来说,处理数据是日常工作中不可或缺的一部分。而Go语言(Golang)作为一种强大且高效的编程语言,提供了许多灵活且易用的数据处理方法。本文将深入探讨G...
    99+
    2023-12-23
    方法 Golang 数据处理
  • 深入探讨Go语言中的数值类型
    go语言中存在4种整数类型,分别为int、int8、int16和int32,用于存储没有小数部分的整数。浮点数类型有float32和float64两种,用于存储带有小数部分的数字。此外,...
    99+
    2024-04-03
    go语言 数值类型
  • 深入探讨:Golang 中的数组交集操作
    golang中获取数组交集有三种方法:使用fmt包的sprint和scanf将数组转换为字符串,并查找一个字符串中包含另一个字符串的元素;使用map包创建一个映射,键为另一个数组中的元素...
    99+
    2024-04-04
    golang 数组交集 python
  • 深入探讨Golang中的泛型概念
    深入探索 Golang 中的泛型概念 前言 Golang 1.18 中引入的泛型是一种强大的语言特性,它允许您在代码中使用类型变量,从而提高代码的可重用性和可维护性。在这篇文章中,我们...
    99+
    2024-04-03
    golang 泛型 键值对
  • 深入探讨 Golang 函数接口与抽象类的异同
    函数接口与抽象类均用于代码可重用性,但实现方式不同:函数接口通过引用函数,抽象类通过继承。函数接口不可实例化,抽象类可实例化。函数接口必须实现所有声明的方法,抽象类可只实现部分方法。 ...
    99+
    2024-04-20
    函数接口 抽象类 golang
  • 深入探讨Go语言中的接口
    Go语言是一种静态类型的编程语言,拥有一套强大的类型系统。在Go语言中,接口(interface)是一个非常重要的概念,它在实现代码的解耦、提升代码的可复用性等方面起着至关重要的作用。...
    99+
    2024-02-25
    go语言 详解
  • 深入探讨Golang中堆栈的差异
    Golang是一门广受欢迎的编程语言,其在并发编程方面拥有独特的设计理念。在Golang中,堆栈(heap和stack)的管理是一项非常重要的任务,对于理解Golang程序的运行机制至...
    99+
    2024-03-13
    golang 堆栈 差异
  • 深入探讨PHP SDK的定义
    PHP SDK(Software Development Kit,软件开发工具包)是一种用于简化开发人员在特定领域或平台上开发应用程序的工具包。它提供了一系列功能和接口,使开发人员能够...
    99+
    2024-03-11
    php sdk 探讨 api调用
  • 深入探索Python中的os.listdir函数
    深入探索Python中的os.listdir函数 1. 引言 在Python中,文件和目录操作是常见的任务之一。而os.listdir()函数是Python中用于获取指定目录下所有文件和子目录的函数之...
    99+
    2023-10-04
    python 开发语言
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作