搜尋
首頁web前端js教程深入探討JavaScript中的async函數
深入探討JavaScript中的async函數Nov 03, 2022 pm 08:36 PM
javascriptasync await

深入探討JavaScript中的async函數

async函數

async函數的回傳值為 promise 對象,promise物件的結果由async函數執行的傳回值決定。 async函數能使得非同步操作變得更方便,簡而言之就是 Generator 的語法糖。

定義async函數,特點是即便函數內部回傳結果不是promise物件,呼叫函數其最後的回傳結果還是promise對象,程式碼如下:

如果傳回的結果不是Promise 物件的情況下:

<script>
    async function fn(){
        // 返回的结果是字符串
        // return &#39;123&#39;
        // // 返回的结果是undefined
        // return;
        // 返回的结果是抛出一个异常
        throw new &#39;error&#39;
    }
    const result = fn()
    console.log(result);
</script>

如果傳回的結果是Promise 對象時,我們正常使用then 方法即可,如下:

<script>
    async function fn(){
        return new Promise((resolve,reject)=>{
            // resolve(&#39;成功的数据&#39;)
            reject(&#39;失败的数据&#39;)
        })
    }
    const result = fn()
    // 调用 then 方法
    result.then((value)=>{
        console.log(value);
    },(reason)=>{
        console.log(reason); // 打印失败的数据
    })
</script>

await 表達式

透過上文的對async 介紹,感覺其功能有點雞肋,其實恰恰不是,而是async 需要搭配await 一起使用才能達到文法糖的效果。

await的特點

#await必須寫在async 函數中

await右邊的表達式一般為promise 物件

await回傳的是promise 成功的值

await的promise 失敗了,就會拋出異常,需要透過try...catch捕獲處理

#說白了:await就相當於then 方法的第一個回呼函數,只回傳成功的值,失敗的值需要try...catch來捕獲。

async函數內部拋出錯誤,會導致傳回的 Promise 物件變成reject狀態。拋出的錯誤物件會被catch方法回呼函數接收到。

<script>
    const p = new Promise((resolve,reject)=>{
        // resolve(&#39;用户数据&#39;)
        reject(&#39;用户加载数据失败了&#39;)
    })
    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(&#39;avatars&#39;);
  }
 
  async getAvatar(name) {
    const cache = await this.cachePromise;
    return cache.match(`/avatars/${name}.jpg`);
  }
}
 
const storage = new Storage();
storage.getAvatar(&#39;jake&#39;).then(…);
 
// 箭头函数
const foo = async () => {};

#async讀取檔案

和先前講解的promise 讀取檔案內容一樣,我們也可以使用async進行檔案的讀取,程式碼如下:

// 1.引入 fs 模块
const fs = require(&#39;fs&#39;)
 
// 2.读取文件
function index(){
    return new Promise((resolve,reject)=>{
        fs.readFile(&#39;./index.md&#39;,(err,data)=>{
            // 如果失败
            if(err) reject(err)
            // 如果成功
            resolve(data)
        })
    })
}
function index1(){
    return new Promise((resolve,reject)=>{
        fs.readFile(&#39;./index1.md&#39;,(err,data)=>{
            // 如果失败
            if(err) reject(err)
            // 如果成功
            resolve(data)
        })
    })
}
function index2(){
    return new Promise((resolve,reject)=>{
        fs.readFile(&#39;./index2.md&#39;,(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(&#39;GET&#39;,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(&#39;hello world&#39;);
        yield &#39;第一分隔线&#39; 
    
        console.log(&#39;hello world 1&#39;);
        yield &#39;第二分隔线&#39;
    
        console.log(&#39;hello world 2&#39;);
        yield &#39;第三分隔线&#39;
    }
    let iterator = person()
    // console.log(iterator); 打印的就是一个迭代器对象,里面有一个 next() 方法,我们借助next方法让它运行
    iterator.next()
    iterator.next()
    iterator.next()
 
    // async函数
    const person1 = async function (){
        console.log(&#39;hello world&#39;);
        await &#39;第一分隔线&#39; 
    
        console.log(&#39;hello world 1&#39;);
        await &#39;第二分隔线&#39;
    
        console.log(&#39;hello world 2&#39;);
        await &#39;第三分隔线&#39;
    }
    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函數的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文轉載於:csdn。如有侵權,請聯絡admin@php.cn刪除
async是es6还是es7的async是es6还是es7的Jan 29, 2023 pm 05:36 PM

async是es7的。async和await是ES7中新增内容,是对于异步操作的解决方案;async/await可以说是co模块和生成器函数的语法糖,用更加清晰的语义解决js异步代码。async顾名思义是“异步”的意思,async用于声明一个函数是异步的;async和await有一个严格规定,两者都离不开对方,且await只能写在async函数中。

es6数组怎么去掉重复并且重新排序es6数组怎么去掉重复并且重新排序May 05, 2022 pm 07:08 PM

去掉重复并排序的方法:1、使用“Array.from(new Set(arr))”或者“[…new Set(arr)]”语句,去掉数组中的重复元素,返回去重后的新数组;2、利用sort()对去重数组进行排序,语法“去重数组.sort()”。

JavaScript的Symbol类型、隐藏属性及全局注册表详解JavaScript的Symbol类型、隐藏属性及全局注册表详解Jun 02, 2022 am 11:50 AM

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于Symbol类型、隐藏属性及全局注册表的相关问题,包括了Symbol类型的描述、Symbol不会隐式转字符串等问题,下面一起来看一下,希望对大家有帮助。

原来利用纯CSS也能实现文字轮播与图片轮播!原来利用纯CSS也能实现文字轮播与图片轮播!Jun 10, 2022 pm 01:00 PM

怎么制作文字轮播与图片轮播?大家第一想到的是不是利用js,其实利用纯CSS也能实现文字轮播与图片轮播,下面来看看实现方法,希望对大家有所帮助!

JavaScript对象的构造函数和new操作符(实例详解)JavaScript对象的构造函数和new操作符(实例详解)May 10, 2022 pm 06:16 PM

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于对象的构造函数和new操作符,构造函数是所有对象的成员方法中,最早被调用的那个,下面一起来看一下吧,希望对大家有帮助。

JavaScript面向对象详细解析之属性描述符JavaScript面向对象详细解析之属性描述符May 27, 2022 pm 05:29 PM

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于面向对象的相关问题,包括了属性描述符、数据描述符、存取描述符等等内容,下面一起来看一下,希望对大家有帮助。

await是es6还是es7的await是es6还是es7的Nov 16, 2022 pm 07:47 PM

await是es7。async和await是ES7中新增内容,是对于异步操作的解决方案。async顾名思义是“异步”的意思,async用于声明一个函数是异步的;而await从字面意思上是“等待”的意思,就是用于等待异步完成。async和await有一个严格规定,两者都离不开对方,且await只能写在async函数中。

javascript怎么移除元素点击事件javascript怎么移除元素点击事件Apr 11, 2022 pm 04:51 PM

方法:1、利用“点击元素对象.unbind("click");”方法,该方法可以移除被选元素的事件处理程序;2、利用“点击元素对象.off("click");”方法,该方法可以移除通过on()方法添加的事件处理程序。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
2 週前By尊渡假赌尊渡假赌尊渡假赌
倉庫:如何復興隊友
4 週前By尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒險:如何獲得巨型種子
4 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SecLists

SecLists

SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。

Safe Exam Browser

Safe Exam Browser

Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。

EditPlus 中文破解版

EditPlus 中文破解版

體積小,語法高亮,不支援程式碼提示功能

mPDF

mPDF

mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),