您好,登錄后才能下訂單哦!
本篇內容介紹了“async屬不屬于es6屬性”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
屬于,async是es6的新特性,用于表明程序里面可能有異步過程。用async關鍵字聲明的函數返回的是一個Promise對象,如果在函數中return一個直接量,async會把這個直接量通過Promise.resolve()封裝成Promise對象;當async函數沒有返回值時,返回“Promise.resolve(undefined)”。
我們先從字面意思來理解這兩個關鍵字,async是asynchronous(異步)的簡寫,而await可以認為是async wait的簡寫。所以async可以理解為用于聲明一個函數是異步的,而await用于等待一個異步任務執行完成。
async和await關鍵字讓我們可以用一種更簡潔的方式寫出基于promise的異步行為,而無需刻意地鏈式調用promise。
接下來我們通過先幾個例子,初步了解一下async和await的作用。
知識點1: 用 async 關鍵字聲明的函數返回的是一個 Promise 對象。如果在函數中 return
一個直接量,async 會把這個直接量通過 Promise.resolve()
封裝成 Promise 對象。當 async
函數沒有返回值時,返回 Promise.resolve(undefined)
//定義一個普通函數,返回一個字符串
function test() {
return "hello async";
}
const result1 = test();
console.log(result1); //輸出一個字符串 hello async
//定義一個使用了async修飾的函數,同樣返回一個字符串
async function testAsync() {
return "hello async";
}
const result2 = testAsync();
console.log(result2); //輸出一個Promise對象 Promise {<fulfilled>: 'hello async'}
//async較好的用法
async function testAsync(){
//返回一個Promise對象
return new Promise((resolve, reject)=>{
//處理異步任務
setTimeout(function () {
resolve("testAsync")
}, 1000);
})
}
//async通常用于聲明一個處理異步任務且返回了Promise對象的函數
知識點2: await關鍵字只能使用在被async聲明的函數內,用于修飾一個Promise對象,使得該Promise對象處理的異步任務在當前協程上按順序同步執行。
//定義一個使用async修飾的函數,處理異步任務
async function testAsync(){
return new Promise((resolve, reject)=>{
setTimeout(function () {
resolve("testAsync")
}, 1000);
})
}
//定義一個函數,直接調用testAsync函數
function testAwait(){
console.log('testAsync調用前')
testAsync().then(res=>{
console.log(res) //輸出"testAsync"
})
console.log('testAsync調用后')
}
/***** 輸出如下 *****/
testAsync調用前
testAsync調用后
testAsync
//盡管代碼按順序寫,但不按順序執行,因為testAsync()是異步函數
//定義一個函數(不使用async聲明該函數)用await修飾調用testAsync函數
function testAwait(){
console.log('testAsync調用前')
await testAsync().then(res=>{ //使用await關鍵字修飾
console.log(res)
})
console.log('testAsync調用后')
}
//調用testAwait()函數
testAwait()
//報錯:Uncaught SyntaxError: await is only valid in async functions and the top level bodies of modules,因為await只能使用在被async修飾的函數內。
//定義一個函數(使用async聲明該函數)用await修飾調用testAsync函數
async function testAwait(){
console.log('testAsync調用前')
await testAsync().then(res=>{
console.log(res)
})
console.log('testAsync調用后')
}
/***** 輸出如下 *****/
testAsync調用前
testAsync
testAsync調用后
//使用了await關鍵字修飾,使得代碼按照順序執行,即同步執行
(1)用于表明程序里面可能有異步過程
(2)async函數返回值的類型為Promise對象: 這是和普通函數本質上不同的地方,也是使用時重點注意的地方;
return newPromise( ),這個用法符合async函數本意;
return data,特別注意到是這樣子寫相當于Promise.resolve(data),返回的data被封裝成一個Promise對象,但是在調用async函數的地方通過簡單的=是拿不到這個返回值data的,因為返回值是一個Promise對象,所以需要用.then(data => { })方式才可以拿到這個data;
如果沒有返回值,相當于返回了Promise.resolve(undefined);
(3)無等待,非阻塞:使用async關鍵字聲明的函數里面如果有異步過程可能會等待,但是函數本身會馬上返回,不會阻塞當前主線程。如果在函數里面使用了await關鍵字修飾的異步過程,其工作在相應的協程上,會阻塞等待異步任務的完成再返回。
//定義一個函數,處理異步任務(使用定時器模擬),返回一個Promise對象
async function testAsync(){
return new Promise((resolve, reject) => {
setTimeout(function () {
resolve("成功調用testAsync")
}, 1000);
});
}
//定義一個函數,使用await關鍵字修飾調用testAsync()函數
async function testAwait(){
//使用了await關鍵字修飾調用testAsyn()函數
await this.testAsync().then(res=>{
console.log(res) //輸出的是testAsync()函數resolve的值
});
console.log("helloAsync");
}
//主線程
console.log('testAwait調用前')
testAwait();
console.log('testAwait調用后')
/***** 輸出結果如下 *****/
testAwait調用前
testAwait調用后 //因為testAwait()函數使用了async關鍵字修飾,所以不會阻塞主線程的執行,所以這兩句話會先直接輸出,然后再執行testAwait()函數
成功調用testAsync //因為testAwait()函數在內部調用testAsync()函數時使用了await關鍵字修飾,所以在對應的協程上會阻塞,等待testAsync()函數執行完,再輸出下面那句'helloAsync'
helloAsync
(1)await只能在async函數內部使用:不能放在普通函數里面,否則會報錯。
(2)await關鍵字后面跟的是一個Promise對象。如果跟的是一個函數,則這個函數應當返回一個Promise對象。如果跟的是非Promise對象,則會通過Promise.resolve( )函數自動將這個東西包裝成一個Promise對象并置于fulfilled狀態。
(3)await的本質是等待它所修飾的Promise對象的fulfilled狀態,并把resolve(data)的數據data返回。 //例如:
const a = await 'Hello Await'
// 相當于
const a = await Promise.resolve('Hello Await');
console.log(a) //輸出 'Hello Await'
意思是,如果await后面跟的是一個 Promise
對象,await
就會阻塞后面的代碼,等著 Promise
對象 resolve
,然后得到 resolve
的值,作為 await
表達式的運算結果。
async function testAsync(){
return new Promise((resolve, reject) => {
setTimeout(function () {
resolve("成功調用testAsync")
}, 1000);
});
}
const a = await testAsync() //這里的a就會拿到testAsync函數resolve的數據
console.log(a) //在一秒后輸出'成功調用testAsync'
(4)await并不關心它所修飾的Promise對象的rejected狀態,即reject(data)的數據data并不會被await處理,所以建議通過Promise對象調用catch去捕獲。
async testAwait(){
//變量a用于接收testAsync()函數resolve的數據
let a = await testAsync().catch(err=>{
//處理異常和reject的數據
})
}
(1)執行順序
①首先打印輸出 //定義一個函數,該函數接收一個參數,1s后再返回參數的兩倍
async function double(num) {
return new Promise((resolve, reject) => {
setTimeout(() => { //使用定時器模擬異步任務
resolve(2 * num) //將運算結果交給resolve
}, 1000);
})
}
async function getResult () {
console.log('double調用前') //順序:2
let result = await double(10); //將10作為參數傳遞給double函數
//result變量用于接收double()函數resolve的值
console.log(result); //順序:4
console.log('double調用后') //順序:4
}
console.log('getResult調用前') //順序:1
getResult();
console.log('getResult調用后') //順序:3
/***** 依次輸出如下 *****/
getResult調用前
double調用前
getResult調用后
20 //1s后輸出
double調用后
getResult調用前
,同步代碼,順序執行;
②然后調用方法getResult( ),打印輸出double調用前
,同步代碼,順序執行;
③再調用異步方法double( )
如果此處沒有使用await關鍵字修飾,則依次輸出的是:getResult調用前、double調用前、double調用后、getResult調用后、1s后輸出20
因為異步操作不會影響其他代碼的執行,所以會將其他代碼按順序執行完,最后再執行double函數
因為這里使用了await關鍵字,所以getResult( )的代碼執行到這里就會被阻塞,等到double函數resolve了,再往下執行
④盡管getResult函數內部被await阻塞了,由于getResult函數本身也是個async函數,所以它不會影響getResult函數外面的代碼執行。因為調用async函數不會造成阻塞,它內部的所有阻塞都被封裝在一個Promise對象中異步執行。
⑤所以在調用getResult函數后,會繼續向下執行,即打印輸出getResult調用后
⑥當1s之后,異步函數double執行完成,將結果交給resolve。
⑦通過await關鍵字接收到double函數resolve的值,賦值給result變量。打印輸出20
⑧因為使用了await阻塞將異步變為同步,所以在打印輸出20后再打印輸出double調用后
(2)處理reject回調
//方法一:通過promise對象的catch進行捕獲
function a(){
return new Promise((resolve,reject) => {
setTimeout(() => {
reject("something")
}, 1000)
})
}
async function b(){
let r = await a().catch((err)=>{
console.log(err)
})
}
//方法二:通過try/catch語句處理
function a(){
return new Promise((resolve,reject) => {
setTimeout(() => {
reject("something")
}, 1000)
})
}
async function b(){
let r = null
try{
r = await a()
}catch(err){
console.log(err)
}
}
(3)使用await優化Promise對象的回調地獄問題
在Promise章節中我們通過了Promise對象的then( )方法鏈式調用解決了回調地獄問題,但看起來仍然不夠美觀,我們可以通過await優化一下,讓它看起來更符合我們平時代碼的編寫習慣。
//原本的解決方案
//第二個請求依賴于第一個請求的返回值,第三個請求依賴于第二個請求的返回值
request1().then(function(data){
return request2(data)
}).then(function(data){
return request3(data)
})
//這里只發送了三次請求,代碼看起來還不錯,雖然它已經比普通的回調函數形式好了很多。
//那如果需要發送五次或十次請求呢?代碼也許會沒那么美觀,接下來我們使用學習到的await去解決這個問題。
原本的要求是每個請求都依賴于上一個請求的返回值,那么是不是得等一個請求完,才能發送下一個請求?這時我們可以思考一下,await的作用是什么?是不是對一個Promise對象去進行阻塞,使其狀態變為fulfilled后獲取resolve的值。這不就正是我們所需要的。
//使用await的解決方案
var res1 = await request1() //將request1的返回值賦值給res1
var res2 = await request2(res1) //將res1作為參數傳給request2,并將request2的返回值賦值給res2
var res3 = await request3(res2) //同理
//這樣子寫的代碼更加的美觀,并且更符合我們平時編寫代碼的習慣
“async屬不屬于es6屬性”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。