溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

JavaScript中異步問題怎么解決

發(fā)布時間:2022-05-07 10:40:54 來源:億速云 閱讀:135 作者:zzz 欄目:大數(shù)據(jù)

本篇內(nèi)容主要講解“JavaScript中異步問題怎么解決”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“JavaScript中異步問題怎么解決”吧!

一、異步解決方案的進化史
JavaScript的異步操作一直是個麻煩事,所以不斷有人提出它的各種解決方案??梢宰匪莸阶钤绲幕卣{(diào)函數(shù)(ajax老朋友),到Promise(不算新的朋友),再到ES6的Generator(強勁的朋友)。
幾年前我們可能用過一個比較著名的Async.js,但是它沒有擺脫回調(diào)函數(shù),并且錯誤處理也是按照“回調(diào)函數(shù)的第一個參數(shù)用來傳遞錯誤”這樣一個約定。而眾所周知的回調(diào)地獄仍然是一個比較突出的問題,直到Generator改變了這種異步風格。
但是ES7的async await的出現(xiàn)(碉堡的新朋友),我們可以輕松寫出同步風格的代碼同時又擁有異步機制,可以說是目前最簡單,最優(yōu)雅,最佳的解決方案了。

二、async await語法
async await語法比較簡單,可以認為是Generator的語法糖,比起星號和yield更具有語義化。下面一個簡單的例子表示1秒之后輸出hello world:

function timeout(ms) {
 return new Promise((resolve) => {
  setTimeout(resolve, ms);
 });
}
async function asyncPrint(value, ms) {
 await timeout(ms);
 console.log(value)
}
asyncPrint('hello world', 1000);

await只能用在async函數(shù)中,如果用在普通函數(shù)就會報錯

await后面跟的是一個Promise對象(當然其它值也可以,但是會包裝成一個立即resolve的Promise,也就沒有意義了)

await會等待Promise的結果返回再繼續(xù)執(zhí)行

await等待的雖然是Promise對象,但是不必寫.then(),直接可以得到返回值,將上面的代碼微調(diào),發(fā)現(xiàn)返回值result也是可以輸出hello world:

function timeout(ms) {
 return new Promise((resolve) => {
  setTimeout(_ => {resolve('hello world')}, ms);
 });
}
async function asyncPrint(ms) {
 let result = await timeout(ms);
 console.log(result)
}
asyncPrint(1000);

三、async await錯誤處理

前面說了await等待的雖然是Promise對象,但是不必寫.then(),所以其實也不用寫.catch()了,直接用try catch就能捕捉錯誤,這樣可以避免錯誤處理代碼非常冗余和笨重,還是將上面的例子微調(diào):

function timeout(ms) {
 return new Promise((resolve, reject) => {
  setTimeout(_ => {reject('error')}, ms);//reject模擬出錯,返回error
 });
}
async function asyncPrint(ms) {
 try {
   console.log('start');
   await timeout(ms);//這里返回了錯誤
   console.log('end');//所以這句代碼不會被執(zhí)行了
 } catch(err) {
   console.log(err); //這里捕捉到錯誤error
 }
}
asyncPrint(1000);

如果有多個await,可以一起放在try catch中:

async function main() {
 try {
  const async1 = await firstAsync();
  const async2 = await secondAsync();
  const async3 = await thirdAsync();
 }
 catch (err) {
  console.error(err);
 }
}

四、async await注意點

1). 前面已經(jīng)說過,await命令后面的Promise對象,運行結果很可能是reject或邏輯報錯,所以最好把await放在try catch代碼塊中。

2). 多個await命令的異步操作,如果不存在依賴關系,讓它們同時觸發(fā)。

const async1 = await firstAsync();
const async2 = await secondAsync();

上面代碼中,async1和async2如果是兩個獨立的異步操作,這樣寫會比較耗時,因為只有firstAsync完成以后,才會執(zhí)行secondAsync,完全可以用Promise.all優(yōu)雅地處理:

let [async1, async2] = await Promise.all([firstAsync(), secondAsync()]);

3). await只能用在async函數(shù)之中,如果用在普通函數(shù)就會報錯:

async function main() {
 let docs = [{}, {}, {}];
 //報錯 await is only valid in async function
 docs.forEach(function (doc) {
  await post(doc);
  console.log('main');
 });
}
function post(){
 return new Promise((resolve) => {
  setTimeout(resolve, 1000);
 });
}

在forEach內(nèi)部方法加上async就可以了:

async function main() {
 let docs = [{}, {}, {}];
 docs.forEach(async function (doc) {
  await post(doc);
  console.log('main');
 });
}
function post(){
 return new Promise((resolve) => {
  setTimeout(resolve, 1000);
 });
}

但是你會發(fā)現(xiàn)3個main是同時輸出的,這就說明post是并發(fā)執(zhí)行的,而不是繼發(fā)執(zhí)行,改成for就可以解決問題,3個main是分別相隔1秒輸出:

async function main() {
 let docs = [{}, {}, {}];
 for (let doc of docs) {
  await post(doc);
  console.log('main');
 }
}
function post(){
 return new Promise((resolve) => {
  setTimeout(resolve, 1000);
 });
}

到此,相信大家對“JavaScript中異步問題怎么解決”有了更深的了解,不妨來實際操作一番吧!這里是億速云網(wǎng)站,更多相關內(nèi)容可以進入相關頻道進行查詢,關注我們,繼續(xù)學習!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。

AI