async異步函數

文章目錄

  • 異步函數(用 async 聲明的函數)
  • 異步函數的返回值
  • async/await 的使用
  • 異步函數的異常處理
  • 總結

感謝鐵子閱讀,覺得有幫助的話點點關注點點贊,謝謝!

異步函數(用 async 聲明的函數)

異步函數的定義
使用async關鍵字聲明的函數,稱之為異步函數。在普通函數前面加上 async 關鍵字,就成了異步函數。語法舉例:

// 寫法1:函數聲明的寫法
async function foo1() {
}// 寫法2:表達式寫法(ES5語法)
const foo2 = async function () {
}// 寫法3:表達式寫法(ES6箭頭函數語法)
const foo3 = async () => {
}// 寫法4:定義一個類,在類中添加一個異步函數
class Person {async foo4() {}
}

JS中的“異步函數”是一個專有名詞,特指用async關鍵字聲明的函數,其他函數則稱之為普通函數。如果你在一個普通函數中定義了一個異步任務,那并不叫異步函數,而是叫包含異步任務的普通函數。

async (異步的)這個單詞是 asynchronous 的縮寫;相反,sync(同步的)這單詞是 synchronous 的縮寫。

上面的異步函數代碼,執行順序與普通函數相同,默認情況下會同步執行。如果想要發揮異步執行的作用,則需要配合 await 關鍵字使用。稍后我們再講 async/await的語法。

異步函數的返回值

異步函數的返回值和普通函數差別比較大,需要特別關注。

普通函數的返回值,默認是 undefined;也可以手動 return 一個返回值,那就以手動 return的值為準。

異步函數的返回值永遠是 Promise 對象。至于這個 Promise 后續會進入什么狀態,那就要看情況了。主要有以下幾種情況:

情況1:如果異步函數內部返回的是普通值(包括 return undefined時)或者普通對象,那么Promise 的狀態為fulfilled。這個值會作為then()回調的參數。
情況2:如果異步函數內部返回的是另外一個新的 Promise,那么 Promise 的狀態將交給新的 Promise 決定。
情況3:如果異步函數內部返回的是一個對象,并且這個對象里有實現then()方法(這種對象稱為 thenable 對象),那就會執行該then()方法,并且根據then()方法的結果來決定Promise的狀態。

另外還有一種特殊情況:

情況4:如果異步函數內部在執行時遇到異常或者手動拋出異常時,那么, Promise 處于rejected 狀態。

上面這四種情況似曾相識,我們在前面學習“resolve() 傳入的參數”、“then()方法的返回值”知識點時,都有類似的情況,知識都是相通的。

默認返回值
代碼舉例:

async function foo2() {// 相當于 return undefined,也相當于 return Promise.resolve(undefined)
};async function foo3() {Promise.resolve('qianguyihao');// 相當于 return undefined,也相當于 return Promise.resolve(undefined)
};// foo2()、foo3()都是一個Promise對象
foo2().then(res => {console.log(res); // 打印結果:undefined
})foo3().then(res => {console.log(res); // 打印結果:undefined
})

代碼解釋:異步函數即便沒有手動寫返回值,也相當于 return Promise.resolve(undefined)。

返回普通值
比如下面這段代碼:

async function foo() {return 'qianguyihao'
};

在這里插入圖片描述
可以看到,foo() 的返回值是Promise對象,不是字符串。上面的代碼等價于下面這段代碼:

async function foo() {return Promise.resolve('qianguyihao');
};

進而,我們可以通過 Promise 對象的then()方法。代碼舉例如下。
舉例1:(異步函數中手動 return 一個值)

async function foo() {return 'qianguyihao';// 上面這行代碼相當于:return Promise.resolve('qianguyihao');
};// foo() 是一個Promise對象
foo().then(res => {console.log(res); // 打印結果:qianguyihao
})

async/await 的使用

異步函數配合 await 關鍵字使用
我們可以在async聲明的異步函數中,使用 await關鍵字來暫停函數的執行,等待一個異步操作完成。溫馨提示:await 關鍵字不能在普通函數中使用,只能在異步函數中使用。

在等待異步操作期間,異步函數會暫停執行,并讓出線程,使其他代碼可以繼續執行。一旦異步操作完成,該異步函數會恢復執行,并返回一個 Promise 對象。具體解釋如下:

(1)await的后面是一個表達式,這個表達式要求是一個 Promise 對象(通常是一個封裝了異步任務的Promise對象)。await執行完成后可以得到異步結果。

(2)await 會等到當前 Promise 的狀態變為 fulfilled之后,才繼續往下執行異步函數。

async 的返回值是 Promise 對象。

本質是語法糖
async/await 是在 ES8(即ES 2017)中引入的新語法,是另外一種異步編程解決方案。

async/await 本質是 生成器 Generator 的語法糖,是對Generator的封裝。什么是語法糖呢?語法糖就是讓語法變得更加簡潔、更加舒服,有一種甜甜的感覺。

async/await 的寫法使得編寫異步代碼更加直觀和易于管理,避免了使用回調函數或Promise鏈的復雜性。認識到這一點,非常重要。

Promise、Generator、async/await的對比
我們在使用 Promise、async/await、Generator 的時候,返回的都是 Promise 的實例。

如果直接使用 Promise,則需要通過 then 來進行鏈式調用;如果使用 async/await、Generator,寫起來更像同步的代碼。

接下來,我們看看 async/await 的代碼是怎么寫的。

async/await 的基本用法
async 后面可以跟一個 Promise 實例對象。代碼舉例如下:

const request1 = function () {const promise = new Promise((resolve, reject) => {requestAjax('https://www.baidu.com/xxx_url', (res) => {if (res.retCode == 200) {// 這里的 res 是接口1的返回結果resolve('request1 success' + res);} else {reject('接口請求失敗');}});});return promise;
};async function requestData() {// 關鍵代碼const res = await request1();return res;
}
requestData().then(res => {console.log(res);
});

用 async/await 封裝Promise鏈式調用【重要】
假設現在有三個網絡請求,請求2必須依賴請求1的結果,請求3必須依賴請求2的結果,如果按照ES5的寫法,會有三層回調,會陷入“回調地獄”。

這種場景其實就是接口的多層嵌套調用。之前學過 Promise,它可以把原本的多層嵌套調用改進為鏈式調用。

而本文要學習的 async/await ,可以把原本的“多層嵌套調用”改成類似于同步的寫法,非常優雅。

代碼舉例:

// 【公共方法層】封裝 ajax 請求的偽代碼。傳入請求地址、請求參數,以及回調函數 success 和 fail。
function requestAjax(url, params, success, fail) {var xhr = new xhrRequest();// 設置請求方法、請求地址。請求地址的格式一般是:'https://api.example.com/data?' + 'key1=value1&key2=value2'xhr.open('GET', url);// 設置請求頭(如果需要)xhr.setRequestHeader('Content-Type', 'application/json');xhr.send();xhr.onreadystatechange = function () {if (xhr.readyState === 4 && xhr.status === 200) {success && success(xhr.responseText);} else {fail && fail(new Error('接口請求失敗'));}};
}// 【model層】將接口請求封裝為 Promise
function requestData1(params_1) {return new Promise((resolve, reject) => {requestAjax('https://api.qianguyihao.com/url_1', params_1, res => {// 這里的 res 是接口返回的數據。返回碼 retCode 為 0 代表接口請求成功。if (res.retCode == 0) {// 接口請求成功時調用resolve('request success' + res);} else {// 接口請求異常時調用reject({ retCode: -1, msg: 'network error' });}});});
}// requestData2、requestData3的寫法與 requestData1類似。他們的請求地址、請求參數、接口返回結果不同,所以需要挨個單獨封裝 Promise。
function requestData2(params_2) {return new Promise((resolve, reject) => {requestAjax('https://api.qianguyihao.com/url_2', params_2, res => {if (res.retCode == 0) {resolve('request success' + res);} else {reject({ retCode: -1, msg: 'network error' });}});});
}function requestData3(params_3) {return new Promise((resolve, reject) => {requestAjax('https://api.qianguyihao.com/url_3', params_3, res => {if (res.retCode == 0) {resolve('request success' + res);} else {reject({ retCode: -1, msg: 'network error' });}});});
}// 封裝:用 async ... await 調用 Promise 鏈式請求
async function getData() {// 【關鍵代碼】const res1 = await requestData1(params_1);const res2 = await requestData2(res1);const res3 = await requestData3(res2);
}getData();

上面這段代碼比較長,我們在上一章學習《Promise的鏈式調用》時,已經詳細講過了。

await 后面也可以跟一個異步函數
前面講到,await后面通常是一個執行異步任務的Promise對象。由于異步函數的返回值本身就是一個Promise,所以,我們也可以在await 后面也可以跟一個異步函數。

代碼舉例:

const request1 = function () {return new Promise((resolve, reject) => {resolve('request1 請求成功');});
};async function request2() {const res = await request1();return res;
}async function request3() {// 【關鍵代碼】request2() 既是一個異步函數,同樣也是一個 Promise,所以可以跟在 await 的后面const res = await request2();console.log('res:', res);
}request3();

異步函數的異常處理

前面講過,如果異步函數內部在執行時遇到異常或者手動拋出異常時,那么, 這個異步函數返回的Promise 處于rejected 狀態。

捕獲并處理異步函數的異常時,有兩種方式:

方式1:通過 Promise的catch()方法捕獲異常。
方式2:通過 try catch捕獲異常。

在處理異步函數的異常情況時,方式2更為常見。

如果我們不捕獲異常,則會往上層層傳遞,最終傳遞給瀏覽器,瀏覽器會在控制臺報錯。

方式1:過 Promise的catch()方法捕獲異常

function requestData1() {return new Promise((resolve, reject) => {reject('任務1失敗');})
}function requestData2() {return new Promise((resolve, reject) => {resolve('任務2成功');})
}async function getData() {// requestData1 在執行時,遇到異常await requestData1();/*由于上面的代碼在執行是遇到異常,所以,這里雖然什么都沒寫,底層默認寫了如下代碼:return Promise.reject('任務1失敗');*/// 下面這行代碼不會再走了await requestData2();
}// getData() 這個異步函數的返回值是一個 Promise,狀態為 rejected,所以會走到 catch()
getData().then(res => {console.log(res);
}).catch(err => {console.log('err:', err);
});

打印結果:

err: 任務1失敗

方式2:通過 try catch 捕獲異常
如果你覺得上面的寫法比較麻煩,還可以通過 try catch 捕獲異常。
代碼舉例:

function requestData1() {return new Promise((resolve, reject) => {reject('任務1失敗');})
}function requestData2() {return new Promise((resolve, reject) => {resolve('任務2成功');})
}async function getData() {try {// requestData1 在執行時,遇到異常await requestData1();/*由于上面的代碼在執行是遇到異常,當前任務立即終止,所以,這里雖然什么都沒寫,底層默認寫了如下代碼:return Promise.reject('任務1失敗');*/// 下面這兩代碼不會再走了console.log('qianguyihao1');await requestData2();}catch (err) {// 捕獲異常代碼console.log('err:', err);}
}getData();
console.log('qianguyihao2');

打印結果:

qianguyihao2
err1: 任務1失敗

總結

在 async 函數中,不是所有的 異步任務都需要 await。如果兩個任務在業務上沒有依賴關系,則不需要 await;也就是說,可以并發執行,不需要線性執行,避免無用的等待。

感謝鐵子閱讀,覺得有幫助的話點點關注點點贊,謝謝!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/36134.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/36134.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/36134.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

yolov8部署資料

1.labelImg安裝: labelImg的安裝過程可以參照以下步驟進行,這里以Windows操作系統為例: 1. 檢查Python環境 首先,需要確認你的電腦上是否已經安裝了Python。你可以通過Win R打開windows“運行”對話框,輸入cmd&#x…

瑤池數據庫SQL-問題二的解決方案

瑤池數據庫SQL-問題二的解決方案 為什么選問題二問題二準備工作解決方案第一步第二步初步嘗試再次嘗試主表自關聯查詢滿足條件數據 解題感受 為什么選問題二 個人沒有詳細的看三個題目的具體內容,只是看了三個題目的題目名稱, 最后覺得問題二比較有意思…

1.1 離散信號的時域分析

目錄 基本離散信號 單位脈沖序列δ[k] 單位階躍序列u[k] 矩形序列Rn[k] 實指數序列x[k] 虛指數序列和正弦序列x[k] 基本運算 翻轉 位移 抽取 內插 卷積 相關 DSP(Digital Signal Processing) 數字信號處理 基本離散信號 單位脈沖序…

目標檢測系列(四)利用pyqt5實現yolov8目標檢測GUI界面

目錄 1、pyqt5安裝 2、PyCharm添加Qt Designer、PyUIC 3、Qt Designer設計界面 4、根據ui文件自動生成py文件 5、修改py文件來調用檢測程序 6、執行py文件啟動 1、pyqt5安裝 Qt Designer:一個用于創建圖形用戶界面的工具,可輕松構建復雜的用戶界面…

linux kernel slab分配器

slab分配器是一種高效的內存管理機制,主要用于小塊內存的分配和釋放。 slab分配器簡述 slab分配器是一種內存管理機制,它將內存分割成多個"緩存"(cache),每個緩存包含固定大小的對象。這些對象可以是內核數據結構、緩沖區或其他小塊內存。 slab分配器用途 高…

還在花錢做數據可視化?為大家推薦一款免費可視化工具

在當今數據驅動的世界里,數據可視化已經成為不可或缺的工具,幫助我們更好地理解和分析信息。然而,許多企業和個人仍在為昂貴的可視化軟件買單,承受著高昂的費用和復雜的操作流程。因此,作為一個經常接觸數據可視化的相…

php聚合快遞寄快遞小程序

一、引言:告別傳統寄件,擁抱便捷新選擇 在數字化時代,我們越來越追求便捷和高效。傳統的寄件方式已經無法滿足現代人快速、便捷的需求。因此,一款聚合快遞優惠寄件小程序應運而生,它集合了多家快遞公司,為…

信創產業生態圈各企業分布

文章目錄 應用系統:辦公管理:云平臺網絡安全基礎軟件操作系統數據庫中間件 基礎硬件芯片 我們國家在前幾年提出了信創戰略計劃,就是為了在信息技術領域,將一些國外牌子的設備和應用、軟件逐漸替換成國產的,保證國家的金…

綜合布線實訓室建設可行性報告

1、 建設綜合布線實訓室的目的和意義 1.1 響應國家職業教育政策 在國家對職業教育的高度重視和政策支持下,綜合布線實訓室的建設不僅是對國家教育方針的積極響應,也是對技術教育改革的有力推動。通過這一平臺,我們旨在培育出一批具有強烈實…

mac app應用程序如何自定義圖標, 更換.app為自己喜歡的圖標或者圖片 詳細圖文講解

在mac系統中,我們可以對任何的app應用程序更換或者自定義圖標, 這個圖標可以是擁有的app的圖標,或者是你自己制作的 x.icns 圖標 或者是 任意的圖片, 建議大小512x512 。 自定義圖標方法如下: 1. 更換為已有app的圖標…

倒計時日期 桌面倒數日 重要日期倒計時提醒

在工作、學習、生活中,我們往往會有很多重要的日子需要我們去標記。在工作中的季度考核、學習中的關鍵時間點、生活中的各種紀念日……等等,都需要我們去對未來這些重要的時間節點做一個倒計時提醒。 日期倒計時讓我們對未來的時間,有一個非…

【深度學習】基于深度離散潛在變量模型的變分推理

1.引言 1.1.討論的目標 閱讀并理解本文后,大家應能夠: 掌握如何為具有離散潛在變量的模型設定參數在可行的情況下,使用精確的對數似然函數來估計參數利用神經變分推斷方法來估計參數 1.2.導入相關軟件包 # 導入PyTorch庫,用于…

揭秘Soundex算法:解鎖聲音背后的數字密碼

文章目錄 引言一、Soundex算法簡介二、Soundex算法的工作原理1.預處理2.初始化3.編碼轉換4.補齊編碼5.匹配計算6.判斷相似得分 三、算法實現代碼Demo四、Soundex算法的應用場景五、Soundex算法的局限性總結 引言 在信息爆炸的今天,數據處理和檢索成為了我們日常生活…

如何在Windows/Mac/Linux上運行Python代碼?

1. 在Windows上運行Python代碼 1.1 安裝Python 1.1.1 從官方網站下載 打開瀏覽器,訪問 Python官網.點擊頁面頂部的“Downloads”按鈕,選擇適用于Windows的版本(一般建議選擇最新穩定版本)。下載完成后,運行安裝程序…

處理key value數據

循環以上數據 <u-popup :round"10" :show"tab OilType" close"close" mode"bottom"><view class"container"><view v-for"(allData, allType) in allList" :key"allType"><view …

注意!流量卡的禁區并不一樣,請看清楚后再下單!

大家好&#xff0c;我是搜卡之家&#xff0c;今天我又來給大家科普了&#xff01; 今天科普的內容是關于流量卡禁區&#xff01; 首先要說一下&#xff0c;流量卡為什么會有禁區&#xff1f;運營商設立禁區主要是為了應對電信詐騙和違法使用電話卡的行為&#xff0c;確保網絡…

Web應用和Tomcat的集成鑒權2-Form Authentication

作者:私語茶館 1.相關章節 1) Web應用和Tomcat的集成鑒權1-BasicAuthentication-CSDN博客 2) Web應用和Tomcat的集成鑒權2-Form Authentication-CSDN博客 集成鑒權+定制化登錄 2.前言 上章講述了Tomcat的Basic Authentication鑒權模式,可以讓Web應用和Tomcat的鑒權集成起來…

【Flink metric(1)】Flink指標系統的系統性知識:獲取metric以及注冊自己的metric

文章目錄 一. Registering metrics&#xff1a;向flink注冊新自己的metrics1. 注冊metrics2. Metric types:指標類型2.1. Counter2.2. Gauge2.3. Histogram(ing)2.4. Meter 二. Scope:指標作用域1. User Scope2. System Scope ing3. User Variables 三. Reporter ing四. System…

面試題-Java垃圾回收之垃圾收集器

1.基礎知識 (1)知識點補充 Stop -the -World:發生時&#xff0c;除了GC所用的線程之外&#xff0c;所有的線程都處于等待狀態 Safepoint: 可達性分析算法時&#xff0c;必須保證在某個快照點進行。 分析的過程中對象的引用關系不會發生變化&#xff01; JVM的運行模式&#x…

數據結構-分析期末選擇題考點(排序)

何似清歌倚桃李 一爐沈水醉紅燈 契子 ? 上一期給大家提供了大概會考的題型給老鐵們復習的大致思路 這一期還會是一樣&#xff0c;我將整理一下排序的題型以及解題方法給你們 由于時間還很多&#xff0c;我就慢慢總結吧&#xff0c;一天一章的樣子&#xff0c;明天總結串、后天…