电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術文章
文章詳情頁

如何優雅地取消 JavaScript 異步任務

瀏覽:102日期:2023-11-07 09:57:37

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

中斷信號

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

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

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

const abortController = new AbortController(); // 1const abortSignal = abortController.signal; // 2fetch( ’http://kaysonli.com’, { signal: abortSignal // 3} ).catch( ( { message } ) => { // 5 console.log( message );} );abortController.abort(); // 4

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

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

可取消的函數

假設有一個執行復雜計算的異步函數,為簡單起見,我們就用定時器模擬:

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>

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

增加中斷異步任務的功能:

{ // 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()函數(4)。

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

在 abort 事件處理器里面清除定時器(7),然后用一個適當的異常對象拒絕 Promise(8)。

根據 DOM 規范,這個異常對象必須是一個’AbortError’ 類型的DOMException。

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

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

const abortController = new AbortController();abortController.abort();calculate( abortController.signal );

這種情況下 abort 事件不會觸發,因為它在signal傳給calculate() 函數前就執行了。為此我們需要改造下代碼:

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()函數應該立即拒絕 Promise,沒必要再往下執行了。到這里我們就實現了一個完整的可取消的異步函數,以后碰到需要處理異步任務的地方就可以派上用場了。

到此這篇關于如何優雅地取消 JavaScript 異步任務的文章就介紹到這了,更多相關JavaScript 取消異步任務內容請搜索好吧啦網以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持好吧啦網!

標簽: JavaScript
相關文章:
主站蜘蛛池模板: 二手电脑回收_二手打印机回收_二手复印机回_硒鼓墨盒回收-广州益美二手电脑回收公司 | 佛山市钱丰金属不锈钢蜂窝板定制厂家|不锈钢装饰线条|不锈钢屏风| 电梯装饰板|不锈钢蜂窝板不锈钢工艺板材厂家佛山市钱丰金属制品有限公司 | 蔬菜清洗机_环速洗菜机_异物去除清洗机_蔬菜清洗机_商用洗菜机 - 环速科技有限公司 | 自进式锚杆-自钻式中空注浆锚杆-洛阳恒诺锚固锚杆生产厂家 | 纸塑分离机-纸塑分离清洗机设备-压力筛-碎浆机厂家金双联环保 | 净气型药品柜-试剂柜-无管道净气型通风柜-苏州毕恩思 | 宁波普瑞思邻苯二甲酸盐检测仪,ROHS2.0检测设备,ROHS2.0测试仪厂家 | ERP企业管理系统永久免费版_在线ERP系统_OA办公_云版软件官网 | 电子元器件呆滞料_元器件临期库存清仓尾料_尾料优选现货采购处理交易商城 | 石牌坊价格石牌坊雕刻制作_石雕牌坊牌楼石栏杆厂家_山东嘉祥石雕有限公司 | 武汉天安盾电子设备有限公司 - 安盾安检,武汉安检门,武汉安检机,武汉金属探测器,武汉测温安检门,武汉X光行李安检机,武汉防爆罐,武汉车底安全检查,武汉液体探测仪,武汉安检防爆设备 | 陶瓷砂磨机,盘式砂磨机,棒销式砂磨机-无锡市少宏粉体科技有限公司 | 深圳美安可自动化设备有限公司,喷码机,定制喷码机,二维码喷码机,深圳喷码机,纸箱喷码机,东莞喷码机 UV喷码机,日期喷码机,鸡蛋喷码机,管芯喷码机,管内壁喷码机,喷码机厂家 | 微量水分测定仪_厂家_卡尔费休微量水分测定仪-淄博库仑 | 杭州中策电线|中策电缆|中策电线|杭州中策电缆|杭州中策电缆永通集团有限公司 | 微型气泵-真空-蠕动-水泵-厂家-深圳市品亚科技有限公司 | 山东锐智科电检测仪器有限公司_超声波测厚仪,涂层测厚仪,里氏硬度计,电火花检漏仪,地下管线探测仪 | 蓝莓施肥机,智能施肥机,自动施肥机,水肥一体化项目,水肥一体机厂家,小型施肥机,圣大节水,滴灌施工方案,山东圣大节水科技有限公司官网17864474793 | 净化车间_洁净厂房_净化公司_净化厂房_无尘室工程_洁净工程装修|改造|施工-深圳净化公司 | 电缆接头_防水接头_电缆防水接头 - 乐清市新豪电气有限公司 | 济南网站建设|济南建网站|济南网站建设公司【济南腾飞网络】【荐】 | 楼承板-开口楼承板-闭口楼承板-无锡海逵 | 武汉宣传片制作-视频拍摄-企业宣传片公司-武汉红年影视 | 玻纤土工格栅_钢塑格栅_PP焊接_单双向塑料土工格栅_复合防裂布厂家_山东大庚工程材料科技有限公司 | 工业车间焊接-整体|集中除尘设备-激光|等离子切割机配套除尘-粉尘烟尘净化治理厂家-山东美蓝环保科技有限公司 | 行吊_电动单梁起重机_双梁起重机_合肥起重机_厂家_合肥市神雕起重机械有限公司 | 接地电阻测试仪[厂家直销]_电缆故障测试仪[精准定位]_耐压测试仪-武汉南电至诚电力设备 | led冷热冲击试验箱_LED高低温冲击试验箱_老化试验箱-爱佩百科 | 铁素体测量仪/检测仪/铁素体含量测试仪-苏州圣光仪器有限公司 | 私人别墅家庭影院系统_家庭影院音响_家庭影院装修设计公司-邦牛影音 | 重庆波纹管|重庆钢带管|重庆塑钢管|重庆联进管道有限公司 | 影视模板素材_原创专业影视实拍视频素材-8k像素素材网 | 污水提升器,污水提升泵,污水提升装置-德国泽德(zehnder)水泵系统有限公司 | 加气混凝土砌块设备,轻质砖设备,蒸养砖设备,新型墙体设备-河南省杜甫机械制造有限公司 | 医养体检包_公卫随访箱_慢病随访包_家签随访包_随访一体机-济南易享医疗科技有限公司 | 污水提升器,污水提升泵,污水提升装置-德国泽德(zehnder)水泵系统有限公司 | 游泳池设备安装工程_恒温泳池设备_儿童游泳池设备厂家_游泳池水处理设备-东莞市君达泳池设备有限公司 | 芝麻黑-芝麻黑石材厂家-永峰石业| 深圳3D打印服务-3D打印加工-手板模型加工厂-悟空打印坊 | 优考试_免费在线考试系统_培训考试系统_题库系统_组卷答题系统_匡优考试 | 交流伺服电机|直流伺服|伺服驱动器|伺服电机-深圳市华科星电气有限公司 |