日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術(shù)文章
文章詳情頁

JavaScript 異步進(jìn)化史

瀏覽:105日期:2023-11-17 16:33:43
前言

JS 中最基礎(chǔ)的異步調(diào)用方式是 callback,它將回調(diào)函數(shù) callback 傳給異步 API,由瀏覽器或 Node 在異步完成后,通知 JS 引擎調(diào)用 callback。對于簡單的異步操作,用 callback 實現(xiàn),是夠用的。但隨著負(fù)責(zé)交互頁面和 Node 出現(xiàn),callback 方案的弊端開始浮現(xiàn)出來。 Promise 規(guī)范孕育而生,并被納入 ES6 的規(guī)范中。后來 ES7 又在 Promise 的基礎(chǔ)上將 async 函數(shù)納入標(biāo)準(zhǔn)。此為 JavaScript 異步進(jìn)化史。

JavaScript 異步進(jìn)化史

同步與異步

通常,代碼是由上往下依次執(zhí)行的。如果有多個任務(wù),就必需排隊,前一個任務(wù)完成,后一個任務(wù)才會執(zhí)行。這種執(zhí)行模式稱之為:同步(synchronous)。新手容易把計算機(jī)用語中的同步,和日常用語中的同步弄混淆。如,“把文件同步到云端”中的同步,指的是“使...保持一致”。而在計算機(jī)中,同步指的是任務(wù)從上往下依次執(zhí)行的模式。比如:

A();B();C();

在這段代碼中,A、B、C是三個不同的函數(shù),每個函數(shù)都是一個不相關(guān)的任務(wù)。在同步模式,計算機(jī)會先執(zhí)行 A 任務(wù),再執(zhí)行 B 任務(wù),最后執(zhí)行 C 任務(wù)。在大部分情況,同步模式都沒問題。但是如果 B 任務(wù)是一個耗時很長的網(wǎng)絡(luò)請求,而 C 任務(wù)恰好是展現(xiàn)新頁面,就會導(dǎo)致網(wǎng)頁卡頓。

更好解決方案是,將 B 任務(wù)分成兩個部分。一部分立即執(zhí)行網(wǎng)絡(luò)請求的任務(wù),另一部分在請求回來后的執(zhí)行任務(wù)。這種一部分立即執(zhí)行,另一部分在未來執(zhí)行的模式稱為異步。

A();// 在現(xiàn)在發(fā)送請求 ajax('url1',function B() { // 在未來某個時刻執(zhí)行})C();// 執(zhí)行順序 A => C => B

實際上,JS 引擎并沒有直接處理網(wǎng)絡(luò)請求的任務(wù),它只是調(diào)用了瀏覽器的網(wǎng)絡(luò)請求接口,由瀏覽器發(fā)送網(wǎng)絡(luò)請求并監(jiān)聽返回的數(shù)據(jù)。JavaScript 異步能力的本質(zhì)是瀏覽器或 Node 的多線程能力。

callback

未來執(zhí)行的函數(shù)通常也叫 callback。使用 callback 的異步模式,解決了阻塞的問題,但是也帶來了一些其他問題。在最開始,我們的函數(shù)是從上往下書寫的,也是從上往下執(zhí)行的,這種“線性”模式,非常符合我們的思維習(xí)慣,但是現(xiàn)在卻被 callback 打斷了!在上面一段代碼中,現(xiàn)在它跳過 B 任務(wù)先執(zhí)行了 C任務(wù)!這種異步“非線性”的代碼會比同步“線性”的代碼,更難閱讀,因此也更容易滋生 BUG。

試著判斷下面這段代碼的執(zhí)行順序,你會對“非線性”代碼比“線性”代碼更難以閱讀,體會更深。

A();ajax('url1', function(){ B(); ajax('url2', function(){C(); } D(); });E();// A => E => B => D => C

這段代碼中,從上往下執(zhí)行的順序被 Callback 打亂了。我們的閱讀代碼視線是A => B => C => D => E,但是執(zhí)行順序卻是A => E => B => D => C,這就是非線性代碼帶來的糟糕之處。

通過將ajax后面執(zhí)行的任務(wù)提前,可以更容易看懂代碼的執(zhí)行順序。雖然代碼因為嵌套看起來不美觀,但現(xiàn)在的執(zhí)行順序卻是從上到下的“線性”方式。這種技巧在寫多重嵌套的代碼時,是非常有用的。

A();E();ajax('url1', function(){ B(); D(); ajax('url2', function(){C(); } });// A => E => B => D => C

上一段代碼只有處理了成功回調(diào),并沒處理異常回調(diào)。接下來,把異常處理回調(diào)加上,再來討論代碼“線性”執(zhí)行的問題。

A();ajax('url1', function(){ B(); ajax('url2', function(){C(); },function(){D(); }); },function(){ E(); });

加上異常處理回調(diào)后,url1的成功回調(diào)函數(shù) B 和異常回調(diào)函數(shù) E,被分開了。這種“非線性”的情況又出現(xiàn)了。

在 node 中,為了解決的異常回調(diào)導(dǎo)致的“非線性”的問題,制定了錯誤優(yōu)先的策略。node 中 callback 的第一個參數(shù),專門用于判斷是否發(fā)生異常

A();get('url1', function(error){ if(error){E(); }else {B();get('url2', function(error){ if(error){D(); }else{C(); }}); }});

到此,callback 引起的“非線性”問題基本得到解決。遺憾的是,使用 callback 嵌套,一層層if else和回調(diào)函數(shù),一旦嵌套層數(shù)多起來,閱讀起來不是很方便。此外,callback 一旦出現(xiàn)異常,只能在當(dāng)前回調(diào)函數(shù)內(nèi)部處理異常。

promise

在 JavaScript 的異步進(jìn)化史中,涌現(xiàn)出一系列解決 callback 弊端的庫,而 Promise 成為了最終的勝者,并成功地被引入了 ES6 中。它將提供了一個更好的“線性”書寫方式,并解決了異步異常只能在當(dāng)前回調(diào)中被捕獲的問題。

Promise 就像一個中介,它承諾會將一個可信任的異步結(jié)果返回。首先 Promise 和異步接口簽訂一個協(xié)議,成功時,調(diào)用resolve函數(shù)通知 Promise,異常時,調(diào)用reject通知 Promise。另一方面 Promise 和 callback 也簽訂一個協(xié)議,由 Promise 在將來返回可信任的值給then和catch中注冊的 callback。

// 創(chuàng)建一個 Promise 實例(異步接口和 Promise 簽訂協(xié)議)var promise = new Promise(function (resolve,reject) { ajax('url',resolve,reject);});// 調(diào)用實例的 then catch 方法 (成功回調(diào)、異常回調(diào)與 Promise 簽訂協(xié)議)promise.then(function(value) { // success}).catch(function (error) { // error})

Promise 是個非常不錯的中介,它只返回可信的信息給 callback。它對第三方異步庫的結(jié)果進(jìn)行了一些加工,保證了 callback 一定會被異步調(diào)用,且只會被調(diào)用一次。

var promise1 = new Promise(function (resolve) { // 可能由于某些原因?qū)е峦秸{(diào)用 resolve('B');});// promise依舊會異步執(zhí)行promise1.then(function(value){ console.log(value)});console.log('A');// A B (先 A 后 B)var promise2 = new Promise(function (resolve) { // 成功回調(diào)被通知了2次 setTimeout(function(){ resolve(); },0)});// promise只會調(diào)用一次promise2.then(function(){ console.log('A')});// A (只有一個)var promise3 = new Promise(function (resolve,reject) { // 成功回調(diào)先被通知,又通知了失敗回調(diào) setTimeout(function(){ resolve(); reject(); },0)});// promise只會調(diào)用成功回調(diào)promise3.then(function(){ console.log('A')}).catch(function(){ console.log('B')});// A(只有A)

介紹完 Promise 的特性后,來看看它如何利用鏈?zhǔn)秸{(diào)用,解決異步代碼可讀性的問題的。

var fetch = function(url){ // 返回一個新的 Promise 實例 return new Promise(function (resolve,reject) {ajax(url,resolve,reject); });}A();fetch('url1').then(function(){ B(); // 返回一個新的 Promise 實例 return fetch('url2');}).catch(function(){ // 異常的時候也可以返回一個新的 Promise 實例 return fetch('url2'); // 使用鏈?zhǔn)綄懛ㄕ{(diào)用這個新的 Promise 實例的 then 方法 }).then(function() { C(); // 繼續(xù)返回一個新的 Promise 實例...})// A B C ...

如此反復(fù),不斷返回一個 Promise 對象,再采用鏈?zhǔn)秸{(diào)用的方式不斷地調(diào)用。使 Promise 擺脫了 callback 層層嵌套的問題和異步代碼“非線性”執(zhí)行的問題。

Promise 解決的另外一個難點是 callback 只能捕獲當(dāng)前錯誤異常。Promise 和 callback 不同,每個 callback 只能知道自己的報錯情況,但 Promise 代理著所有的 callback,所有 callback 的報錯,都可以由 Promise 統(tǒng)一處理。所以,可以通過catch來捕獲之前未捕獲的異常。

Promise 解決了 callback 的異步調(diào)用問題,但 Promise 并沒有擺脫 callback,它只是將 callback 放到一個可以信任的中間機(jī)構(gòu),這個中間機(jī)構(gòu)去鏈接我們的代碼和異步接口。

異步(async)函數(shù)

異步(async)函數(shù)是 ES7 的一個新的特性,它結(jié)合了 Promise,讓我們擺脫 callback 的束縛,直接用類同步的“線性”方式,寫異步函數(shù)。

聲明異步函數(shù),只需在普通函數(shù)前添加一個關(guān)鍵字 async 即可,如async function main(){} 。在異步函數(shù)中,可以使用await關(guān)鍵字,表示等待后面表達(dá)式的執(zhí)行結(jié)果,一般后面的表達(dá)式是 Promise 實例。

async function main{ // timer 是在上一個例子中定義的 var value = await timer(100); console.log(value); // done (100ms 后返回 done)}main();

異步函數(shù)和普通函數(shù)一樣調(diào)用 main() 。調(diào)用后,會立即執(zhí)行異步函數(shù)中的第一行代碼 var value = await timer(100) 。等到異步執(zhí)行完成后,才會執(zhí)行下一行代碼。

除此之外,異步函數(shù)和其他函數(shù)基本類似,它使用try...catch來捕捉異常。也可以傳入?yún)?shù)。但不要在異步函數(shù)中使用return來返回值。

var timer = new Promise(function create(resolve,reject) { if(typeof delay !== 'number'){ reject(new Error('type error')); } setTimeout(resolve,delay,'done');});async function main(delay){ try{ var value1 = await timer(delay); var value2 = await timer(''); var value3 = await timer(delay); }catch(err){ console.error(err); // Error: type error // at create (<anonymous>:5:14) // at timer (<anonymous>:3:10) // at A (<anonymous>:12:10) }}main(0);

異步函數(shù)也可以被當(dāng)作值,傳入普通函數(shù)和異步函數(shù)中執(zhí)行。但是在異步函數(shù)中,使用異步函數(shù)時要注意,如果不使用await,異步函數(shù)會被同步執(zhí)行。

async function main(delay){ var value1 = await timer(delay); console.log('A')}async function doAsync(main){ main(0); console.log('B')}doAsync(main);// B A

這個時候打印出來的值是 B A。說明 doAsync 函數(shù)并沒有等待 main 的異步執(zhí)行完畢就執(zhí)行了 console。如果要讓 console 在 main 的異步執(zhí)行完畢后才執(zhí)行,我們需要在main前添加關(guān)鍵字await。

async function main(delay){ var value1 = await timer(delay); console.log('A')}async function doAsync(main){ await main(0); console.log('B')}doAsync(main);// A B

由于異步函數(shù)采用類同步的書寫方法,所以在處理多個并發(fā)請求,新手可能會像下面一樣書寫。這樣會導(dǎo)致url2的請求必需等到url1的請求回來后才會發(fā)送。

var fetch = function (url) { return new Promise(function (resolve,reject) { ajax(url,resolve,reject); });}async function main(){ try{ var value1 = await fetch('url1'); var value2 = await fetch('url2'); conosle.log(value1,value2); }catch(err){ console.error(err) }}main();

使用Promise.all的方法來解決這個問題。Promise.all用于將多個Promise實例,包裝成一個新的 Promis e實例,當(dāng)所有的 Promise 成功后才會觸發(fā)Promise.all的resolve函數(shù),當(dāng)有一個失敗,則立即調(diào)用Promise.all的reject函數(shù)。

var fetch = function (url) { return new Promise(function (resolve,reject) { ajax(url,resolve,reject); });}async function main(){ try{ var arrValue = await Promise.all[fetch('url1'),fetch('url2')]; conosle.log(arrValue[0],arrValue[1]); }catch(err){ console.error(err) }}main();

目前使用 Babel 已經(jīng)支持 ES7 異步函數(shù)的轉(zhuǎn)碼了,大家可以在自己的項目中開始嘗試。

標(biāo)簽: JavaScript
相關(guān)文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
亚洲精品小说| 亚洲一区av| 91一区二区三区四区| 欧美国产另类| 精品久久影院| 亚洲特级毛片| 国产字幕视频一区二区| 中文不卡在线| 日韩中文字幕不卡| 国产精品永久| 91视频久久| 日韩欧美国产精品综合嫩v| 亚洲二区三区不卡| 欧美午夜不卡| 亚洲精品高潮| 麻豆一区二区三区| 日韩理论视频| 欧美日韩精品一本二本三本| 亚洲欧美日本国产专区一区| 日韩不卡在线观看日韩不卡视频 | 老牛影视一区二区三区| 天堂а√在线最新版中文在线| 激情国产在线| 国产美女一区| 欧美经典一区| 理论片午夜视频在线观看| 91精品啪在线观看国产18| 国产日韩视频在线| 99精品99| 一级欧美视频| 精品亚洲精品| 亚洲综合不卡| 精品一区二区三区的国产在线观看| 性欧美长视频| 亚洲欧美网站在线观看| 国产黄色一区| 玖玖精品视频| 国产精品永久| 久久国产成人午夜av影院宅| 快she精品国产999| 成人在线视频免费| 日韩高清不卡一区二区| 精品丝袜久久| 石原莉奈在线亚洲二区| 日本不卡不码高清免费观看| 久久久久国产精品一区二区| 免费日韩av片| 高清久久精品| 亚洲精品麻豆| 99精品电影| 国产美女精品视频免费播放软件| 六月婷婷一区| 欧美国产另类| 亚洲一区二区三区高清| 久久精品三级| 亚洲精品伊人| 国产高清一区| 国产伦久视频在线观看| 日韩三级一区| 免费不卡中文字幕在线| 精品三级av| 日韩不卡手机在线v区| 免费黄色成人| 日本一区二区高清不卡| 国产精品分类| 蜜桃视频欧美| av最新在线| 蜜桃精品视频| 热久久久久久| 伊人精品久久| 在线综合亚洲| 99久久精品费精品国产| 国产高清精品二区| 亚洲日本三级| 欧美成人基地| 久久理论电影| 美女性感视频久久| 日韩av一区二| 综合国产在线| 久久av一区| 国产精品av久久久久久麻豆网| 久久久久久久久99精品大| 欧美偷窥清纯综合图区| 最新亚洲一区| 欧美一区二区三区高清视频| 成人亚洲一区二区| 韩国女主播一区二区三区| 国产欧美日韩精品高清二区综合区| 精品视频一区二区三区在线观看 | 国产精品亚洲二区| 亚洲女同中文字幕| 丝袜av一区| 日韩在线综合| 色黄视频在线观看| 亚洲综合电影| 精品免费av在线| 欧美日韩国产v| 香蕉视频亚洲一级| 99久久99久久精品国产片果冰| 亚洲在线成人| 1024精品久久久久久久久| 国产精品99久久精品| 精品国产亚洲一区二区在线观看| 国产一区二区三区自拍| 久久婷婷丁香| 久久久久蜜桃| 免费国产自久久久久三四区久久| 日韩黄色免费网站| 亚洲精品免费观看| 日本免费在线视频不卡一不卡二| 成人免费网站www网站高清| 日产精品一区二区| 91欧美在线| 视频福利一区| 日韩中文字幕不卡| 日韩毛片一区| 国产精品传媒麻豆hd| 成人亚洲精品| 欧美日韩一区二区三区视频播放| 日韩激情一区二区| 欧美日韩精品一区二区三区视频 | 亚洲精品激情| 亚洲v天堂v手机在线| 日韩在线成人| 国产精品大片| 99久久久久久中文字幕一区| 夜夜嗨av一区二区三区网站四季av| 国产福利一区二区精品秒拍| 久久精品一区二区国产| 日韩国产欧美| 99re国产精品| 国产情侣久久| 日韩大片在线播放| 久久亚洲欧美| 国产精品a级| 欧洲亚洲一区二区三区| 99re国产精品| 国产精品第一| 亚洲一级网站| 日本成人在线视频网站| 热三久草你在线| 免费精品视频最新在线| 国产精品久久久久久久久免费高清| 性色av一区二区怡红| 欧美日韩一区二区三区四区在线观看| 亚洲天堂久久| 亚洲精品在线二区| 国产拍在线视频| 日韩精品一二区| 国内精品美女在线观看| 亚洲一区二区三区四区五区午夜| 欧美羞羞视频| 在线看片日韩| 免费在线欧美黄色| 99亚洲视频| 国产精品视频首页| 五月天久久网站| 国产精品亚洲综合在线观看| 亚洲国产一区二区在线观看| 国产高清视频一区二区| 99国产精品99久久久久久粉嫩| 国产99精品| 日韩精品免费视频一区二区三区| 亚洲欧美日韩专区| 日韩精品一区二区三区av| av综合电影网站| 日本aⅴ免费视频一区二区三区| 日韩高清二区| 日韩国产综合| 国产乱码精品一区二区三区四区 | 欧美日韩一区二区三区在线电影| 日韩精品一级中文字幕精品视频免费观看| 亚洲精品在线影院| 在线一区二区三区视频| 成人免费电影网址| 日韩高清不卡一区二区| 激情五月综合| 国产传媒在线观看| 日韩1区2区日韩1区2区| 激情综合网站| 国产精品麻豆久久| 国产精品videossex| 亚洲精品乱码久久久久久蜜桃麻豆| 日本高清久久| 尤物在线精品| 午夜av成人| 欧美国产三级| 日韩精品一区二区三区中文字幕| 国产精品一区二区三区美女| 99久久99久久精品国产片果冰 | www在线观看黄色| 欧美日韩国产一区二区在线观看| 91亚洲精品在看在线观看高清| 日韩激情视频网站| 日本久久成人网| 免费看欧美美女黄的网站| 91精品国产91久久久久久黑人| 在线视频日韩| 久久婷婷一区| 99视频精品全国免费|