最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

如何優(yōu)雅地取消 JavaScript 異步任務(wù)

 更新時間:2020年03月22日 16:27:07   作者:KaysonLi  
這篇文章主要介紹了如何優(yōu)雅地取消 JavaScript 異步任務(wù),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

在程序中處理異步任務(wù)通常比較麻煩,尤其是那些不支持取消異步任務(wù)的編程語言。所幸的是,JavaScript 提供了一種非常方便的機(jī)制來取消異步任務(wù)。

中斷信號

自從 ES2015 引入了  Promise ,開發(fā)者有了取消異步任務(wù)的需求,隨后推出的一些 Web API 也開始支持異步方案,比如 Fetch API。TC39 委員會(就是制定 ECMAScript 標(biāo)準(zhǔn)的組織)最初嘗試定義一套通用的解決方案,以便后續(xù)作為 ECMAScript 標(biāo)準(zhǔn)。但是后來討論不出什么結(jié)果來,這個問題也就擱置了。鑒于此,WHATWG (HTML 標(biāo)準(zhǔn)制定組織)另起爐灶,自己搞出一套解決方案,直接在 DOM 標(biāo)準(zhǔn)上引入了 AbortController。這種做法的壞處顯而易見,因?yàn)樗皇钦Z言層面的 ECMAScript 標(biāo)準(zhǔn),因此 Node.js 平臺也就不支持  AbortController 。

在 DOM  規(guī)范里, AbortController 設(shè)計(jì)得非常通用,因此事實(shí)上你可以用在任何異步 API 中。目前只得到 Fetch API 的官方支持,但你完全可以用在自己的異步代碼里。

在開始介紹之前,我們先看下 AbortController 的工作原理:

const abortController = new AbortController(); // 1
const abortSignal = abortController.signal; // 2

fetch( 'http://kaysonli.com', {
 signal: abortSignal // 3
} ).catch( ( { message } ) => { // 5
 console.log( message );
} );

abortController.abort(); // 4

上面的代碼很簡單,首先創(chuàng)建了AbortController的一個實(shí)例(1),并將它的 signal 屬性賦值給一個變量(2)。然后調(diào)用fetch()并傳入 signal 參數(shù)(3)。取消請求時調(diào)用 abortController.abort()(4)。這樣就會自動執(zhí)行fetch() 的 reject ,也就是進(jìn)入catch()部分(5)。

它的signal屬性是核心所在。該屬性是 AbortSignal DOM 接口的實(shí)例,它有一個 aborted屬性,帶有是否調(diào)用了 abortController.abort()的相關(guān)信息。還可以在上面監(jiān)聽abort事件,該事件在abortController.abort()調(diào)用時觸發(fā)。簡單來說,AbortController 就是AbortSignal的一個公開接口。

可取消的函數(shù)

假設(shè)有一個執(zhí)行復(fù)雜計(jì)算的異步函數(shù),為簡單起見,我們就用定時器模擬:

function calculate() {
 return new Promise( ( resolve, reject ) => {
  setTimeout( ()=> {
   resolve( 1 );
  }, 5000 );
 } );
}

calculate().then( ( result ) => {
 console.log( result );
} );

可能的情況是,用戶想取消這種耗時的任務(wù)。我們用一個按鈕來開始和停止:

<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>

上面的代碼給按鈕綁定了一個異步的 click 事件處理器(1),并在里面調(diào)用了 calculate() 函數(shù)(2)。5 秒后會彈出對話框顯示結(jié)果(3)。順便提一下,script[type=module]可以讓 JavaScript 代碼進(jìn)入嚴(yán)格模式,跟 'use strict' 的效果一樣。

增加中斷異步任務(wù)的功能:

{ // 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)相當(dāng)于一個 IIFE(立即執(zhí)行的函數(shù)表達(dá)式),這樣變量 abortController(2)就不會污染全局了。

首先把它的值設(shè)為null,并且它的值隨著按鈕點(diǎn)擊而改變。隨后給它賦值為AbortController的一個實(shí)例(3),再把實(shí)例的signal屬性直接傳給 calculate()函數(shù)(4)。

如果用戶在 5 秒之內(nèi)再次點(diǎn)擊按鈕,就會執(zhí)行abortController.abort()函數(shù)(5)。這樣就會在剛才傳給 calculate()的AbortSignal實(shí)例上觸發(fā) abort 事件(6)。

在 abort 事件處理器里面清除定時器(7),然后用一個適當(dāng)?shù)漠惓ο缶芙^ Promise(8)。

根據(jù) DOM 規(guī)范,這個異常對象必須是一個'AbortError' 類型的DOMException。

這個異常對象最終傳給了catch (9) 和finally (10)。

但是還要考慮這樣一種情況:

const abortController = new AbortController();

abortController.abort();
calculate( abortController.signal );

這種情況下 abort 事件不會觸發(fā),因?yàn)樗趕ignal傳給calculate() 函數(shù)前就執(zhí)行了。為此我們需要改造下代碼:

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),這樣就可以在兩個地方重用了。另外,多了個條件判斷abortSignal.aborted(2)。如果它的值是true,calculate()函數(shù)應(yīng)該立即拒絕 Promise,沒必要再往下執(zhí)行了。
到這里我們就實(shí)現(xiàn)了一個完整的可取消的異步函數(shù),以后碰到需要處理異步任務(wù)的地方就可以派上用場了。

到此這篇關(guān)于如何優(yōu)雅地取消 JavaScript 異步任務(wù)的文章就介紹到這了,更多相關(guān)JavaScript 取消異步任務(wù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • js中如何往對象中添加屬性

    js中如何往對象中添加屬性

    這篇文章主要介紹了js中如何往對象中添加屬性,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-10-10
  • 如何讓js中的if判斷如絲般順滑詳解

    如何讓js中的if判斷如絲般順滑詳解

    條件判斷語句是程序開發(fā)過程中一種經(jīng)常使用的語句形式,和大部分編程語言相同,JavaScript 中也有條件判斷語句,這篇文章主要給大家介紹了關(guān)于如何讓js中的if判斷如絲般順滑的相關(guān)資料,需要的朋友可以參考下
    2021-10-10
  • 循環(huán) vs 遞歸淺談

    循環(huán) vs 遞歸淺談

    本文代碼使用 JavaScript。 一些同學(xué)對遞歸的理解還停留在“是一種求階乘比循環(huán)低效的方法”。但其實(shí)遞歸和循環(huán)處理的問題是不同。拿“遍歷數(shù)組”這個問題來說:循環(huán)適合同一維度(單層長度不限)上的遍歷,而遞歸則適合跨維度(層數(shù)不限)的遍歷。
    2013-02-02
  • JavaScript 拖拽與觀察者模式的實(shí)現(xiàn)及應(yīng)用小結(jié)

    JavaScript 拖拽與觀察者模式的實(shí)現(xiàn)及應(yīng)用小結(jié)

    本文通過代碼片段詳細(xì)介紹了JavaScript中的拖拽功能和觀察者模式(發(fā)布-訂閱模式)的實(shí)現(xiàn)及其應(yīng)用場景,拖拽功能允許用戶通過鼠標(biāo)移動元素,而觀察者模式則定義了一種一對多的依賴關(guān)系,使得對象能夠自動更新,感興趣的朋友跟隨小編一起看看吧
    2025-01-01
  • JavaScript實(shí)現(xiàn)多維數(shù)組的方法

    JavaScript實(shí)現(xiàn)多維數(shù)組的方法

    這篇文章主要介紹了JavaScript實(shí)現(xiàn)多維數(shù)組的方法,有需要的朋友可以參考一下
    2013-11-11
  • JavaScript設(shè)計(jì)模式---單例模式詳解【四種基本形式】

    JavaScript設(shè)計(jì)模式---單例模式詳解【四種基本形式】

    這篇文章主要介紹了JavaScript設(shè)計(jì)模式---單例模式,結(jié)合實(shí)例形式詳細(xì)分析了JavaScript設(shè)模式中單例模式的四種基本形式定義與使用方法,需要的朋友可以參考下
    2020-05-05
  • 解決Layui數(shù)據(jù)表格中checkbox位置不居中的方法

    解決Layui數(shù)據(jù)表格中checkbox位置不居中的方法

    今天小編就為大家分享一篇解決Layui數(shù)據(jù)表格中checkbox位置不居中的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-08-08
  • 全面解析JavaScript中“&&”和“||”操作符(總結(jié)篇)

    全面解析JavaScript中“&&”和“||”操作符(總結(jié)篇)

    這篇文章主要介紹了全面解析JavaScript中“&&”和“||”操作符(總結(jié)篇)的相關(guān)資料,需要的朋友可以參考下
    2016-07-07
  • 前端如何用post的方式進(jìn)行eventSource請求

    前端如何用post的方式進(jìn)行eventSource請求

    這篇文章主要給大家介紹了關(guān)于前端如何用post的方式進(jìn)行eventSource請求的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2023-04-04
  • 第九章之路徑分頁標(biāo)簽與徽章組件

    第九章之路徑分頁標(biāo)簽與徽章組件

    Bootstrap,來自 Twitter,是目前最受歡迎的前端框架。本文給大家介紹路徑分頁標(biāo)簽與徽章組件,感興趣的朋友一起學(xué)習(xí)吧
    2016-04-04

最新評論

阿拉善左旗| 化德县| 太仓市| 大竹县| 嘉黎县| 改则县| 平塘县| 依安县| 涿州市| 洪洞县| 盐源县| 上犹县| 石家庄市| 冀州市| 南宫市| 千阳县| 林甸县| 仪陇县| 屏东市| 射洪县| 金昌市| 兖州市| 和田县| 海兴县| 穆棱市| 黄浦区| 原阳县| 延津县| 安阳市| 台东县| 武定县| 开远市| 望城县| 上饶县| 揭阳市| 临桂县| 宿松县| 呼玛县| 台江县| 柳州市| 东城区|