- 資訊首頁(yè) > 開(kāi)發(fā)技術(shù) >
- JavaScript中怎么處理異步
JavaScript中怎么處理異步,相信很多沒(méi)有經(jīng)驗的人對此束手無(wú)策,為此本文總結了問(wèn)題出現的原因和解決方法,通過(guò)這篇文章希望你能解決這個(gè)問(wèn)題。
一、回調函數
回調是一個(gè)函數被作為一個(gè)參數傳遞到另一個(gè)函數里,在那個(gè)函數執行完后再執行?;卣{函數是異步編程最基本的方法,其優(yōu)點(diǎn)是簡(jiǎn)單、容易理解和部署;缺點(diǎn)是容易產(chǎn)生回調地獄。
ajax('XXX1', () => { // callback 函數體 ajax('XXX2', () => { // callback 函數體 ajax('XXX3', () => { // callback 函數體 }) }) })
這就是所謂的回調地獄,回調地獄帶來(lái)的負面作用有以下幾點(diǎn):
代碼臃腫,可讀性差,可維護性差。
代碼復用性差。
容易滋生 bug。
只能在回調里處理異常。
二、事件監聽(tīng)
這種方式,異步任務(wù)的執行不取決于代碼的順序,而取決于某個(gè)事件是否發(fā)生。
(1) 普通方式
f1.on('done', f2);
上面這行代碼的意思是,當f1發(fā)生done事件,就執行f2。
(2) onclick方法
element.onclick=function(){ //處理函數 } element.onclick=handler1; element.onclick=handler2; element.onclick=handler3; // 只有handler3會(huì )被添加執行
優(yōu)點(diǎn):寫(xiě)法兼容到主流瀏覽器;
缺點(diǎn):當同一個(gè)element元素綁定多個(gè)事件時(shí),只有最后一個(gè)事件會(huì )被添加
(3) addEvenListener
elment.addEvenListener("click",handler1,false); elment.addEvenListener("click",handler2,false); elment.addEvenListener("click",handler3,false);
該方法的第三個(gè)參數是一個(gè)布爾值:當為false時(shí)表示由里向外,true表示由外向里。
三、發(fā)布/訂閱模式
我們假定,存在一個(gè)"信號中心",某個(gè)任務(wù)執行完成,就向信號中心"發(fā)布"(publish)一個(gè)信號,其他任務(wù)可以向信號中心"訂閱"(subscribe)這個(gè)信號,從而知道什么時(shí)候自己可以開(kāi)始執行。這就叫做"發(fā)布/訂閱模式"(publish-subscribe pattern)
首先,f2向信號中心jQuery訂閱done信號。
jQuery.subscribe('done', f2);
然后,f1進(jìn)行如下改寫(xiě):
function f1() { setTimeout(function () { jQuery.publish('done'); }, 1000); }
f1執行完成后,向信號中心jQuery發(fā)布done信號,從而引發(fā)f2的執行。f2完成執行后,可以取消訂閱(unsubscribe)
jQuery.unsubscribe('done', f2);
這種方式的優(yōu)點(diǎn):可以通過(guò)查看“消息中心”,了解存在多少信號、每個(gè)信號有多少訂閱者,從而監控程序的運行。
四、promise
以上都是ES6之前的異步處理方式。ES6之后出現了promise。它是異步編程的一種解決方案,比傳統的解決方案(回調函數)——更合理和更強大。
Promise 對象有以下兩個(gè)特點(diǎn)。
對象的狀態(tài)不受外界影響。Promise 對象代表一個(gè)異步操作,有三種狀態(tài):pending(進(jìn)行中)、fulfilled(已成功)和rejected(已失敗)。只有異步操作的結果,可以決定當前是哪一種狀態(tài),任何其他操作都無(wú)法改變這個(gè)狀態(tài)。
一旦狀態(tài)改變,就不會(huì )再變,任何時(shí)候都可以得到這個(gè)結果
1. 基本用法
(1) ES6 規定,Promise 對象是一個(gè)構造函數,用來(lái)生成 Promise 實(shí)例。
const promise = new Promise((resolve, reject) => { if (/* 異步操作成功 */){ resolve(success) } else { reject(error) } })
Promise接收一個(gè)函數作為參數,函數里有resolve和reject兩個(gè)參數:
resolve方法的作用是將Promise的pending狀態(tài)變?yōu)閒ullfilled,在異步操作成功之后調用,可以將異步返回的結果作為參數傳遞出去。
reject方法的作用是將Promise的pending狀態(tài)變?yōu)閞ejected,在異步操作失敗之后調用,可以將異步返回的結果作為參數傳遞出去。
他們之間只能有一個(gè)被執行,不會(huì )同時(shí)被執行,因為Promise只能保持一種狀態(tài)。
(2) Promise 實(shí)例生成以后,可以用then方法分別指定resolved狀態(tài)和rejected狀態(tài)的回調函數。
promise.then((success) => { // 對應于上面的resolve(success)方法 }, (error) => { // 對應于上面的reject(error)方法 } // 還可以寫(xiě)成這樣 (推薦使用這種寫(xiě)法) promise.then((success) => { // 對應于上面的resolve(success)方法 }).catch((error) => { // 對應于上面的reject(error)方法 })
then(onfulfilled,onrejected)方法中有兩個(gè)參數,兩個(gè)參數都是函數:
第一個(gè)參數執行的是resolve()方法(即異步成功后的回調方法)
第二參數執行的是reject()方法(即異步失敗后的回調方法)(第二個(gè)參數可選)。
它返回的是一個(gè)新的Promise對象。
(3) promise構造函數是同步執行的,then方法是異步執行的
const promise = new Promise((resolve, reject) => { console.log(1) resolve() console.log(2) }) promise.then(() => { console.log(3) }) console.log(4) // 1 2 4 3
2. Promise.finally()
Promise.finally()用于指定不管 Promise 對象最后狀態(tài)如何,都會(huì )執行的操作。
promise .then(result => {···}) .catch(error => {···}) .finally(() => {···});
3. Promise.all()
Promise.all()用于處理多個(gè)異步處理,比如說(shuō)一個(gè)頁(yè)面上需要等多個(gè) ajax 的數據回來(lái)才執行相關(guān)邏輯。
const p = Promise.all([p1, p2, p3]);
p的狀態(tài)由p1、p2、p3決定,分成兩種情況。
只有p1、p2、p3的狀態(tài)都變成fulfilled,p的狀態(tài)才會(huì )變成fulfilled,此時(shí)p1、p2、p3的返回值組成一個(gè)數組,傳遞給p的回調函數。
只要p1、p2、p3之中有一個(gè)被rejected,p的狀態(tài)就變成rejected,此時(shí)第一個(gè)被reject的實(shí)例的返回值,會(huì )傳遞給p的回調函數。
4. Promse.race()
Promse.race()就是賽跑的意思,Promise.race([p1, p2, p3])里面哪個(gè)結果獲得的快,就返回那個(gè)結果,不管結果本身是成功狀態(tài)還是失敗狀態(tài)。
const p = Promise.race([p1, p2, p3])
上面代碼中,只要p1、p2、p3之中有一個(gè)實(shí)例率先改變狀態(tài),p的狀態(tài)就跟著(zhù)改變。那個(gè)率先改變的 Promise 實(shí)例的返回值,就傳遞給p的回調函數。
五、async/await
async/await是JavaScript為了解決異步問(wèn)題而提出的一種解決方案,許多人將其稱(chēng)為異步的終極解決方案。async 函數,就是 Generator 函數的語(yǔ)法糖。
相較于 Generator,Async 函數的改進(jìn)在于下面四點(diǎn):
內置執行器。Generator 函數的執行必須依靠執行器,而 Aysnc 函數自帶執行器,調用方式跟普通函數的調用一樣。
更好的語(yǔ)義。async 和 await 相較于 * 和 yield 更加語(yǔ)義化。
更廣的適用性。co 模塊約定,yield 命令后面只能是 Thunk 函數或 Promise對象。而 async 函數的 await 命令后面可以是 Promise 或者原始類(lèi)型(Number,string,boolean,但這時(shí)等同于同步)。
返回值是 Promise。async 函數返回值是 Promise 對象,比 Generator 函數返回的 Iterator 對象方便,可以直接使用 then() 方法進(jìn)行調用。
1. 使用規則
(1) 凡是在前面添加了async的函數在執行后都會(huì )自動(dòng)返回一個(gè)Promise對象
async function test() { } let result = test() console.log(result) //即便代碼里test函數什么都沒(méi)返回,我們依然打出了Promise對象
(2) await必須在async函數里使用,不能單獨使用
function test() { let result = await Promise.resolve('success') console.log(result) } test() //執行以后會(huì )報錯
2. await 在等什么
如果await等到的不是一個(gè)promise對象,那跟著(zhù)的表達式的運算結果就是它等到的東西;
如果是一個(gè)promise對象,await會(huì )阻塞后面的代碼,等promise對象resolve,得到resolve的值作為await表達式的運算結果
雖然await阻塞了,但await在async中,async不會(huì )阻塞,它內部所有的阻塞都被封裝在一個(gè)promise對象中異步執行
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自互聯(lián)網(wǎng)轉載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權請聯(lián)系QQ:712375056 進(jìn)行舉報,并提供相關(guān)證據,一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容。
Copyright ? 2009-2021 56dr.com. All Rights Reserved. 特網(wǎng)科技 特網(wǎng)云 版權所有 珠海市特網(wǎng)科技有限公司 粵ICP備16109289號
域名注冊服務(wù)機構:阿里云計算有限公司(萬(wàn)網(wǎng)) 域名服務(wù)機構:煙臺帝思普網(wǎng)絡(luò )科技有限公司(DNSPod) CDN服務(wù):阿里云計算有限公司 中國互聯(lián)網(wǎng)舉報中心 增值電信業(yè)務(wù)經(jīng)營(yíng)許可證B2
建議您使用Chrome、Firefox、Edge、IE10及以上版本和360等主流瀏覽器瀏覽本網(wǎng)站