<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
async函數的返回值為 promise 物件,promise物件的結果由async函數執行的返回值決定。async函數能使得非同步操作變得更加方便,簡而言之就是 Generator 的語法糖。
定義async函數,特點是即便函數內部返回結果不是promise物件,呼叫函數其最後的返回結果依然是promise物件,程式碼如下:
如果返回的結果不是 Promise 物件的情況下:
<script> async function fn(){ // 返回的結果是字串 // return '123' // // 返回的結果是undefined // return; // 返回的結果是丟擲一個異常 throw new 'error' } const result = fn() console.log(result); </script>
如果返回的結果是 Promise 物件時,我們正常使用 then 方法即可,如下:
<script> async function fn(){ return new Promise((resolve,reject)=>{ // resolve('成功的資料') reject('失敗的資料') }) } const result = fn() // 呼叫 then 方法 result.then((value)=>{ console.log(value); },(reason)=>{ console.log(reason); // 列印失敗的資料 }) </script>
通過上文的對 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('使用者資料') 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 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 () => {};
和之前講解的 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()
和之前講解 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>
我們發現 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非同步程式設計中async函數詳解的文章就介紹到這了,更多相關JS async內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45