国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 開發(fā) > JS > 正文

JavaScript體驗(yàn)異步更好的解決辦法

2024-05-06 16:41:51
字體:
供稿:網(wǎng)友

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

二、async await語(yǔ)法
async await語(yǔ)法比較簡(jiǎn)單,可以認(rèn)為是Generator的語(yǔ)法糖,比起星號(hào)和yield更具有語(yǔ)義化。下面一個(gè)簡(jiǎn)單的例子表示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ù)就會(huì)報(bào)錯(cuò)

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

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

await等待的雖然是Promise對(duì)象,但是不必寫.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錯(cuò)誤處理

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

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

如果有多個(gè)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注意點(diǎn)

1). 前面已經(jīng)說過,await命令后面的Promise對(duì)象,運(yùn)行結(jié)果很可能是reject或邏輯報(bào)錯(cuò),所以最好把a(bǔ)wait放在try catch代碼塊中。

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

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

上面代碼中,async1和async2如果是兩個(gè)獨(dú)立的異步操作,這樣寫會(huì)比較耗時(shí),因?yàn)橹挥衒irstAsync完成以后,才會(huì)執(zhí)行secondAsync,完全可以用Promise.all優(yōu)雅地處理:

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

3). await只能用在async函數(shù)之中,如果用在普通函數(shù)就會(huì)報(bào)錯(cuò):

async function main() { let docs = [{}, {}, {}]; //報(bào)錯(cuò) 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); });}

但是你會(huì)發(fā)現(xiàn)3個(gè)main是同時(shí)輸出的,這就說明post是并發(fā)執(zhí)行的,而不是繼發(fā)執(zhí)行,改成for就可以解決問題,3個(gè)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); });}

總之,用了async await之后整個(gè)人神清氣爽,可以用非常簡(jiǎn)潔和優(yōu)雅的代碼實(shí)現(xiàn)各種花式異步操作,并且在業(yè)務(wù)邏輯復(fù)雜的情況下可以不用陷入回調(diào)地獄中。不敢說這一定是終極的解決方案,但確實(shí)是目前最優(yōu)雅的解決方案!

 

注:相關(guān)教程知識(shí)閱讀請(qǐng)移步到JavaScript/Ajax教程頻道。
發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 宜良县| 绍兴县| 乡宁县| 绥芬河市| 西乌珠穆沁旗| 平果县| 绥江县| 常熟市| 惠安县| 康乐县| 黄石市| 英吉沙县| 清镇市| 山东| 吕梁市| 巴林左旗| 新乡县| 邯郸市| 越西县| 陆良县| 平湖市| 彭州市| 萨迦县| 嘉峪关市| 明星| 山东省| 芒康县| 高青县| 武宣县| 桐乡市| 鹤山市| 博兴县| 元阳县| 凤台县| 岳西县| 中超| 松溪县| 余庆县| 兴和县| 太白县| 靖远县|