【JS異步編程】async/await——用同步代碼寫異步

歷史小劇場

懂得暴力的人,是強壯的;懂得克制暴力的人,才是強大的。----《明朝那些事兒》

什么是 async/await

  • async: 聲明一個異步函數
    • 自動將常規函數轉換成Promise,返回值也是一個Promise對象;
    • 只有async函數內部的異步操作執行完,才會執行then方法指定的回調函數;
    • 異步函數內部可以使用await
  • await: 暫停異步的功能執行
    • 放置在Promise調用之前,await強制其他代碼等待,直到Promise完成并返回結果;
    • 只能與Promise一起使用,不適用回調;
    • 只能在async函數內部使用

簡單使用

async function fun() {// let name = await "后盾人"// console.log(name) let name = await new Promise(resolve => {setTimeout(() => {resolve("后盾人")}, 1000)})let site = await new Promise(resolve => {setTimeout(() => {resolve("www.houdunren.com")}, 2000)})console.log("name => ", name)console.log("site => ", site)}// console.log(fun()) // Promise {<fulfilled>: undefined}// fun().then(value => console.log(value))fun()

聲明方式

  1. 普通函數
async function get(dictType) {const dict = await ajax(`http://xxx?dict=${dictType}`)console.log("dict => ", dict)
}
  1. 函數表達式
const foo = async function (dictType) {const dict = await ajax(`http://xxx?dict=${dictType}`)console.log("dict => ", dict)
}
  1. 箭頭函數
const foo = async () => {const dict = await ajax(`http://xxx?dict=${dictType}`)console.log("dict => ", dict)
}
  1. 對象
let obj = {async get() {const dict = await ajax(`http://xxx?dict=${dictType}`)console.log("dict => ", dict)}
}
  1. class 類
class Dict {constructor(dictType) {this.dictType = dictType}async get() {let dictList = await ajax(`http://xxx?dict=${this.dictType}`)dictList.data.forEach(dictItem => {dictItem.AREA_NAME += '-心潮'})return dictList.data;}
}
new Dict('DICT_DRUG_AREA').get().then(value => {console.log("value => ", value)
})

錯誤處理

  1. async錯誤處理
async function get() {console.log(a)
}
get().catch(error => {console.log("error => ", error) // error =>  ReferenceError: a is not defined
})async function get2() {throw new Error("用戶不存在")
}
get2().catch(error => {console.log("error2 => ", error) // error2 =>  Error: 用戶不存在
})
  1. await 錯誤處理
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><script src="../js/ajax.js"></script><script>// 1、在函數外部處理// async function get(dictType) {//     let dictList = await ajax(`ahttp://xxx?dict=${dictType}`)//     return dictList;// }// get('DICT_DRUG_AREA').then(res => {//     console.log("res => ", res.data)// }).catch(error => {//     console.log("error => ", error.message)// })// 2、在函數內部處理async function get(dictType) {try {let dictList = await ajax(`ahttp://xxx?dict=${dictType}`)return dictList;} catch (error) {alert(error.message)}}get('DICT_DRUG_AREA').then(res => {console.log("res => ", res.data)})</script>
</body>
</html>

ajax.js文件

class ParamError extends Error {constructor(msg) {super(msg)this.name = 'ParamError'}
}class HttpError extends Error {constructor(msg) {super(msg)this.name = 'HttpError'}
}function ajax(url) {// 自定義錯誤處理if (!/^http/.test(url)) {throw new ParamError("請求地址格式錯誤")}return new Promise((resolve, reject) => {let xhr = new XMLHttpRequest();xhr.open("POST", url)xhr.send()xhr.onload = function () {if (this.status === 200) {resolve(JSON.parse(this.response))} else if (this.status === 404) {// 自定義錯誤處理reject(new HttpError("響應內容不存在"))} else {reject("加載失敗")}}xhr.onerror = function () {reject(this)}})
}

場景案例

1. async延時函數
const sleep = async (delay = 2000) => {return new Promise(resolve => {setTimeout(() => {resolve()}, delay)})
}const show = async () => {for (name of ['小芳', '小紅']) {await sleep()console.log(name)}
}
show()
2. await 進度條
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>* {margin: 0;padding: 0;}#loading {width: 0vw;background-color: blueviolet;height: 10vh;display: flex;color: white;align-items: center;justify-content: center;transition: all 1s ease-out;font-size: 20px;}</style>
</head>
<body><div id="loading">0%</div><script src="../js/ajax.js"></script><script>(async (dicts) => {const loading = document.querySelector("#loading");for (let i = 0, len = dicts.length; i < len; i++) {await ajax(`http://xxx?dict=${dicts[i]}`)loading.style.width = `${(i + 1) / len * 100}vw`loading.textContent = `${Math.round((i + 1) / len * 100)}%`}})(Array(50).fill('DICT_DRUG_AREA'))</script>
</body>
</html>
3. await 并行技巧

首先,這里,有兩個異步任務

function p1() {return new Promise(resolve => {setTimeout(() => {resolve("p1")}, 2000)})
}function p2() {return new Promise(resolve => {setTimeout(() => {resolve("p2")}, 2000)})
}

當我們正常使用時,會順序隔兩秒打印p1和p2,代碼如下:

// 按順序打印
async function fun() {let p1value = await p1()console.log(p1value)let p2value = await p2()console.log(p2value)
}
fun()

顯然,這不是我們想要的效果。接著,我們這樣修改

fun()// 過兩秒之后 并行打印
async function fun() {let p1value = p1()let p2value = p2()setTimeout(() => {console.log(p1value)        // Promise { 'p1' }console.log(p2value)        // Promise { 'p2' }}, 2000)
}

這里,我們沒有使用await,那么返回的是Promise對象。
如上代碼,運行之后,會隔兩秒鐘之后同時打印 Promise { ‘p1’ } 和 Promise { ‘p2’ }

這樣,我們就找到了并行打印技巧

方案一

async function fun() {let p1fun = p1()let p2fun = p2()let p1value = await p1funlet p2value = await p2funconsole.log(p1value)        // p1console.log(p2value)        // p2
}

方案二 (推薦)

async function fun2() {const res = await Promise.all([p1(), p2()])console.log("res => ", res)     // res =>  [ 'p1', 'p2' ]
}
fun2()

小結

Async/Await讓我們用少量的代碼來使用Promise,我們可以將一些有依賴關系的回調函數的處理邏輯放在async里面,然后在非async的區域使用,這樣可以減少then或者catch回調。

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

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

相關文章

Java SE入門及基礎(59) 線程的實現(上) 線程的創建方式 線程內存模型 線程安全

目錄 線程&#xff08;上&#xff09; 1. 線程的創建方式 Thread類常用構造方法 Thread類常用成員方法 Thread類常用靜態方法 示例 總結 2. 線程內存模型 3.線程安全 案例 代碼實現 執行結果 線程&#xff08;上&#xff09; 1. 線程的創建方式 An application t…

利用 Docker 簡化 Nacos 部署:快速搭建 Nacos 服務

利用 Docker 簡化 Nacos 部署&#xff1a;快速搭建 Nacos 服務 引言 在微服務架構中&#xff0c;服務注冊與發現是確保服務間通信順暢的關鍵組件。Nacos&#xff08;Dynamic Naming and Configuration Service&#xff09;作為阿里巴巴開源的一個服務發現和配置管理平臺&…

任務調度器——任務切換

一、開啟任務調度器 函數原型&#xff1a; void vTaskStartScheduler( void ) 作用&#xff1a;用于啟動任務調度器&#xff0c;任務調度器啟動后&#xff0c; FreeRTOS 便會開始進行任務調度 內部實現機制&#xff08;以動態創建為例&#xff09;&#xff1a; &#xff0…

Linux 安裝、配置Tomcat 的HTTPS

Linux 安裝 、配置Tomcat的HTTPS 安裝Tomcat 這里選擇的是 tomcat 10.X ,需要Java 11及更高版本 下載頁 ->Binary Distributions ->Core->選擇 tar.gz包 下載、上傳到內網服務器 /opt 目錄tar -xzf 解壓將解壓的根目錄改名為 tomat-10 并移動到 /opt 下, 形成個人…

測評推薦:企業管理u盤的軟件有哪些?

U盤作為一種便攜的存儲設備&#xff0c;方便易用&#xff0c;被廣泛應用于企業辦公、個人學習及日常工作中。然而&#xff0c;U盤的使用也帶來了數據泄露、病毒傳播等安全隱患。為了解決這些問題&#xff0c;企業管理U盤的軟件應運而生。 本文將對市面上流行的幾款U盤管理軟件…

Hadoop3:Yarn容量調度器配置多隊列案例

一、情景描述 需求1&#xff1a; default隊列占總內存的40%&#xff0c;最大資源容量占總資源60%&#xff0c;hive隊列占總內存的60%&#xff0c;最大資源容量占總資源80%。 二、多隊列優點 &#xff08;1&#xff09;因為擔心員工不小心&#xff0c;寫遞歸死循環代碼&#…

數據處理:四選一、四關聯

今天去面試&#xff0c;面試官們給我一個‘選擇’&#xff0c;有四個選項&#xff1a;‘展示你的才華’、‘展示你的美貌’、‘展示你的才華與美貌’、‘都不展示’ {label: “選擇”,children: [{label: “展示你的才華”,children: [],isShow: talentModal,click: () > {i…

電路筆記(電源模塊): 基于FT2232HL實現的jtag下載器硬件+jtag的通信引腳說明

JTAG接口說明 JTAG 接口根據需求可以選擇20針或14針的配置&#xff0c;具體選擇取決于應用場景和需要連接的功能。比如之前的可編程邏輯器件XC9572XL使用JTAG引腳&#xff08;TCK、TDI、TDO、TMS、VREF、GND&#xff09;用于與器件進行調試和編程通信。更詳細的內容可以閱讀11…

51單片機STC8H8K64U通過RA8889/RA8876如何控制彩屏(SPI源碼下載)

【硬件部份】 一、硬件連接實物&#xff1a; STC8H系列單片機不需要外部晶振和外部復位&#xff0c;在相同的工作頻率下&#xff0c;速度比傳統的8051單片機要快12倍&#xff0c;具有高可靠抗干擾的優秀特性&#xff0c;與瑞佑的RA8889/RA8876控制芯片剛好可以完美搭配用于工…

redis實戰-緩存雪崩問題及解決方案

定義理解 緩存雪崩是指在同一時間段&#xff0c;大量緩存的key同時失效&#xff0c;或者Redis服務宕機&#xff0c;導致大量請求到達數據庫&#xff0c;帶來巨大壓力 和緩存擊穿的區別&#xff1a; 緩存雪崩是由于緩存中的大量數據同時失效或緩存服務器故障引起的&#xff1b…

(漏洞檢查項) | 服務端請求偽造 SSRF

(漏洞檢查項)|服務端請求偽造 SSRF 漏洞場景 服務端請求偽造&#xff08;SSRF&#xff0c;Server-Side Request Forgery&#xff09;漏洞發生在應用程序允許攻擊者通過構造惡意請求&#xff0c;利用服務器端發起HTTP請求&#xff0c;并訪問內部資源或進行其他未授權操作。 漏…

css_20_定位

相對定位 設置相對定位 給元素設置 position: relative 即可實現相對定位。 可以使用 left、right、top 、 bottom 四個屬性調整位置。 相對定位的參考點是相對自己原來的位置相對定位的特點&#xff1a; 1&#xff0e;不會脫離文檔流&#xff0c;元素位置的變化&#xff0c;只…

機器學習周記(第四十五周:Graphformer)2024.6.24~2024.6.30

目錄 摘要ABSTRACT1 論文信息1.1 論文標題1.2 論文摘要1.3 論文引言1.4 論文貢獻 2 論文模型2.1 問題定義2.2 模型架構2.2.1 自注意下采樣模塊&#xff08;Self-attention down-sampling module&#xff09;2.2.2 稀疏圖自注意力機制&#xff08;Sparse graph self-attention m…

python自動移除excel文件密碼(小工具)

安裝 msoffcrypto-tool 使用pip命令安裝: 打開命令行工具&#xff08;如終端、命令提示符或Powershell&#xff09;&#xff0c;然后輸入以下命令來安裝msoffcrypto-tool&#xff1a; pip install msoffcrypto-tool庫&#xff0c;進行自動移除excel文件密碼 import msoffcrypt…

【C++】using namespace std 到底什么意思

&#x1f4e2;博客主頁&#xff1a;https://blog.csdn.net/2301_779549673 &#x1f4e2;歡迎點贊 &#x1f44d; 收藏 ?留言 &#x1f4dd; 如有錯誤敬請指正&#xff01; &#x1f4e2;本文作為 JohnKi 的學習筆記&#xff0c;引用了部分大佬的案例 &#x1f4e2;未來很長&a…

新手練習項目 7:猜數字游戲

名人說&#xff1a;莫聽穿林打葉聲&#xff0c;何妨吟嘯且徐行。—— 蘇軾《定風波莫聽穿林打葉聲》 Code_流蘇(CSDN)&#xff08;一個喜歡古詩詞和編程的Coder&#xff09; 目錄 一、項目描述二、項目實現三、項目步驟四、項目擴展方向 更多項目內容&#xff0c;請關注我、訂…

comsol學習筆記

comsol巖土力學與流固耦合的學習 comsol的相關視頻教程 https://www.bilibili.com/video/BV1Cu4y1r7Gn/?spm_id_from333.337.search-card.all.click&vd_source02b2bad477a153eaeb9c48cbbedaf8df [這里面有講解地應力平衡技術] https://www.bilibili.com/video/BV17C4y1j…

打靶記錄——靶機medium_socnet

靶機下載地址 https://www.vulnhub.com/entry/boredhackerblog-social-network,454/ 打靶過程 由于靶機和我的Kali都處于同一個網段&#xff0c;所以使用arpscan二次發現技術來識別目標主機的IP地址 arpscan -l除了192.168.174.133&#xff0c;其他IP都是我VMware虛擬機正…

【Spring Boot】認識 JPA 的接口

認識 JPA 的接口 1.JPA 接口 JpaRepository2.分頁排序接口 PagingAndSortingRepository3.數據操作接口 CrudRepository4.分頁接口 Pageable 和 Page5.排序類 Sort JPA 提供了操作數據庫的接口。在開發過程中繼承和使用這些接口&#xff0c;可簡化現有的持久化開發工作。可以使 …

springboot學習,如何用redission實現分布式鎖

目錄 一、springboot框架介紹二、redission是什么三、什么是分布式鎖四、如何用redission實現分布式鎖 一、springboot框架介紹 Spring Boot是一個開源的Java框架&#xff0c;由Pivotal團隊&#xff08;現為VMware的一部分&#xff09;于2013年推出。它旨在簡化Spring應用程序…