這篇文章將為大家詳細講解有關JavaScript取消異步任務的方法,文章內容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。

成都創(chuàng)新互聯(lián)公司長期為上1000家客戶提供的網站建設服務,團隊從業(yè)經驗10年,關注不同地域、不同群體,并針對不同對象提供差異化的產品和服務;打造開放共贏平臺,與合作伙伴共同營造健康的互聯(lián)網生態(tài)環(huán)境。為平武企業(yè)提供專業(yè)的網站設計、網站制作,平武網站改版等技術服務。擁有十余年豐富建站經驗和眾多成功案例,為您定制開發(fā)。
在等待數(shù)據(jù)返回這段時間,JavaScript是不能處理其他任務的,此時頁面的交互,滾動等任何操作也都會被阻塞,這顯然是及其不友好,不可接受的,而這正是需要異步編程大顯身手的場景。我們想通過Ajax請求數(shù)據(jù)來渲染頁面,這是一個在我們前端當中很常見渲染頁面的方式。基本每 個頁面都會都這樣的過程。
中止信號(Abort signal)
在將 Promise 引入 ES2015 并出現(xiàn)了一些支持新異步解決方案的 Web API 之后不久,需要取消異步任務的需求就出現(xiàn)了。最初的嘗試集中在創(chuàng)建通用解決方案上,并期待以后可以成為 ECMAScript 標準的一部分。但是,討論很快陷入僵局,無法解決問題。因此,WHATWG 準備了自己的解決方案,并以 AbortController 的形式將其直接引入 DOM。這種解決方案的明顯缺點是 Node.js 中不提供 AbortController,從而在該環(huán)境沒有任何優(yōu)雅或官方的方式來取消異步任務。
正如你在 DOM 規(guī)范中所看到的,AbortController 是用一種非常通用的方式描述的。所以你可以在任何類型的異步 API 中使用 —— 甚至是那些目前還不存在的 API。目前只有 Fetch API 正式支持,但是你也可以在自己的代碼中使用它!
在開始之前,讓我們花點時間分析一下 AbortController 的工作原理:
const abortController = new AbortController(); // 1
const abortSignal = abortController.signal; // 2
fetch( 'http://example.com', {
signal: abortSignal // 3
} ).catch( ( { message } ) => { // 5
console.log( message );
} );
abortController.abort(); // 4查看上面的代碼,你會發(fā)現(xiàn)在開始時創(chuàng)建了 AbortController DOM 接口的新實例(1),并將其 signal 屬性綁定到變量(2)。然后調用 fetch() 并傳遞 signal 作為其選項之一(3)。要中止獲取資源,你只需調用abortController.abort()(4)。它將自動拒絕 fetch()的 promise,并且控件將傳遞給 catch()塊(5)。
signal 屬性本身非常有趣,它是該節(jié)目的主要明星。該屬性是 AbortSignal DOM 接口的實例,該實例具有 aborted 屬性,其中包含有關用戶是否已調用 abortController.abort() 方法的信息。你還可以將 abort 事件偵聽器綁定到將要調用 abortController.abort() 時調用的事件監(jiān)聽器。換句話說:AbortController 只是 AbortSignal 的公共接口。
可終止函數(shù)
假設我們用一個異步函數(shù)執(zhí)行一些非常復雜的計算(例如,異步處理來自大數(shù)組的數(shù)據(jù))。為簡單起見,示例函數(shù)通過先等待五秒鐘然后再返回結果來模擬這一工作:
function calculate() {
return new Promise( ( resolve, reject ) => {
setTimeout( ()=> {
resolve( 1 );
}, 5000 );
} );
}
calculate().then( ( result ) => {
console.log( result );
} );但有時用戶希望能夠中止這種代價高昂的操作。沒錯,他們應該有這樣的能力。添加一個能夠啟動和停止計算的按鈕:
<button id="calculate">Calculate</button>
<script type="module">
document.querySelector('#calculate').addEventListener('click',async({ target })=>{//1
target.innerText = 'Stop calculation';
const result = await calculate(); // 2
alert( result ); // 3
target.innerText = 'Calculate';
} );
function calculate() {
return new Promise( ( resolve, reject ) => {
setTimeout( ()=> {
resolve( 1 );
}, 5000 );
} );
}
</script>在上面的代碼中,向按鈕(1)添加一個異步 click 事件偵聽器,并在其中調用 calculate() 函數(shù)(2)。五秒鐘后,將顯示帶有結果的警報對話框(3)。另外, script [type = module] 用于強制 JavaScript 代碼進入嚴格模式——因為它比 'use strict' 編譯指示更為優(yōu)雅。
現(xiàn)在添加中止異步任務的功能:
{ // 1
let abortController = null; // 2
document.querySelector('#calculate').addEventListener('click',async ( { target } )=>{
if ( abortController ) {
abortController.abort(); // 5
abortController = null;
target.innerText = 'Calculate';
return;
}
abortController = new AbortController(); // 3
target.innerText = 'Stop calculation';
try {
const result = await calculate( abortController.signal ); // 4
alert( result );
} catch {
alert( 'WHY DID YOU DO THAT?!' ); // 9
} finally { // 10
abortController = null;
target.innerText = 'Calculate';
}
} );
function calculate( abortSignal ) {
return new Promise( ( resolve, reject ) => {
const timeout = setTimeout( ()=> {
resolve( 1 );
}, 5000 );
abortSignal.addEventListener( 'abort', () => { // 6
const error = new DOMException(
'Calculation aborted by the user', 'AbortError'
);
clearTimeout( timeout ); // 7
reject( error ); // 8
} );
} );
}
}如你所見,代碼變得更長了。但是沒有理由驚慌,它并沒有變得更難理解!
一切都包含在塊(1)中,該塊相當于IIFE。因此,abortController 變量(2)不會泄漏到全局作用域內。
首先,將其值設置為 null 。鼠標單擊按鈕時,此值會更改。然后將其值設置為 AbortController 的新實例(3)。之后,將實例的 signal 屬性直接傳遞給你的 calculate() 函數(shù)(4)。
如果用戶在五秒鐘之內再次單擊該按鈕,則將導致調用 abortController.abort() 函數(shù)(5)。反過來,這將在你先前傳遞給 calculate() 的 AbortSignal 實例上觸發(fā) abort 事件(6)。
在 abort 事件偵聽器內部,刪除了滴答計時器(7)并拒絕了帶有適當錯誤的promise (8; 根據(jù)規(guī)范 ,它必須是類型為 'AbortError' 的 DOMException)。該錯誤最終把控制權傳遞給 catch(9)和 finally 塊(10)。
你還應該準備處理如下情況的代碼:
const abortController = new AbortController(); abortController.abort(); calculate( abortController.signal );
在這種情況下,abort 事件將不會被觸發(fā),因為它發(fā)生在將信號傳遞給 calculate() 函數(shù)之前。因此你應該進行一些重構:
function calculate( abortSignal ) {
return new Promise( ( resolve, reject ) => {
const error = new DOMException(
'Calculation aborted by the user', 'AbortError'
); // 1
if ( abortSignal.aborted ) { // 2
return reject( error );
}
const timeout = setTimeout( ()=> {
resolve( 1 );
}, 5000 );
abortSignal.addEventListener( 'abort', () => {
clearTimeout( timeout );
reject( error );
} );
} );
}錯誤被移到頂部(1)。因此,你可以在代碼不同部分中重用它(但是,創(chuàng)建一個錯誤工廠會更優(yōu)雅,盡管聽起來很愚蠢)。另外出現(xiàn)了一個保護子句,檢查 abortSignal.aborted(2)的值。如果等于 true,那么 calculate() 函數(shù)將會拒絕帶有適當錯誤的 promise,而無需執(zhí)行任何其他操作。
關于JavaScript取消異步任務的方法就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
分享標題:JavaScript取消異步任務的方法
本文路徑:http://chinadenli.net/article24/ggpgje.html
成都網站建設公司_創(chuàng)新互聯(lián),為您提供、Google、品牌網站制作、定制網站、電子商務、面包屑導航
聲明:本網站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)