<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      [轉] 異步任務取消機制

      異步任務取消機制

      作者:謝杰

      該文章是并發異步操作系列文章第一篇。

      為什么需要取消異步任務

      在現代的 Web 和 Node.js 應用中,我們經常需要啟動一些耗時較長的異步任務,比如:

      • 下載大文件
      • 進行高強度的計算
      • 持續監聽一個長時間的事件流

      然而,一旦任務開始運行,傳統上我們只能等待它結束或因異常而中斷。在很多情況下,這并不理想,因為我們可能需要主動終止任務,例如:

      • 用戶已經切換到其他頁面,不再關心結果
      • 請求超時
      • 用戶點擊了“取消”操作

      在早期的 Web API 中,XHR 提供過 .abort() 方法,但基于 Promise 的 fetch() 等 API 最初并沒有類似的能力。

      為了填補這一空白,WHATWG 在 2017 年將 AbortControllerAbortSignal 納入 DOM Standard,作為統一的取消信號機制。

      和早期的 XHR 的實現所不同的是,早期的 XHR 里的 .abort() 方法,這是 XHR 自己實現的取消邏輯,其他 API 用不了。AbortController 則是 WHATWG 定義的統一標準,任何 API 只要愿意支持,都可以接收它的 signal 來實現取消(例如 fetchReadableStream、Node.js 的 fs.readFilesetTimeout 等等)。

      雖然它最初出現在瀏覽器端,但這套設計與 DOM 并非深度耦合,只依賴于事件派發機制,因此 Node.js 自 v15.0.0(2020 年)起原生支持了 AbortControllerAbortSignal(低于 v15 的版本可通過 node-abort-controller 等 polyfill 實現兼容)。如今,你可以在 Node 環境下的 fetch()streamtimers 等異步 API 中,使用與瀏覽器一致的取消方案。

      快速上手

      接下來我們來看一下核心 API,有兩個:

      • AbortController
      • AbortSignal

      為啥會有兩個呢?來看下面的圖:

      image-20250808161836438

      上面的示意圖展示了 AbortController 與 AbortSignal 的工作原理。

      在沒有取消機制時(上圖),客戶端發起異步請求后,只能一直等待服務器完成耗時處理,即便中途不再需要結果,也無能為力。

      引入取消機制后(下圖),AbortController 就像一只“遙控器”,可以在任務執行過程中隨時發出 AbortSignal。異步任務收到信號后,會立即停止執行,從而避免無意義的等待和資源消耗。

      你可以將這套設計理解為:

      • Controller:信號的發射端
      • Signal:信號的接收端

      這種模式讓異步任務的生命周期可控,在請求超時、用戶主動取消或頁面切換等場景下,都能優雅、安全地終止任務。

      下面來看一下代碼層面具體該怎么寫:

      // 創建一個 AbortController 實例,用于管理和發出取消信號
      const controller = new AbortController();
      
      // 從控制器中獲取對應的 AbortSignal 對象
      // 這個 signal 會被傳遞給需要支持取消的 API
      const signal = controller.signal;
      
      // 使用 fetch 發送請求,并在配置中傳入 signal
      // 一旦 signal 被觸發(abort),fetch 會立即中止
      fetch("https://example.com", { signal })
        .then(res => {
          // 當請求正常完成時會進入這里
          console.log("請求成功");
        })
        .catch(err => {
          // 如果是因為調用了 controller.abort() 而中斷,會返回 AbortError 類型的錯誤
          if (err.name === "AbortError") {
            console.log("請求被中斷");
          } else {
            // 其他類型的錯誤,例如網絡錯誤或服務器返回非 2xx 狀態碼
            console.error("請求發生錯誤", err);
          }
        });
      
      // 模擬延遲 2 秒后手動中止請求
      // 當執行 controller.abort() 時,會觸發 signal 的中止狀態
      // 已經關聯了這個 signal 的 fetch 請求會被立即終止
      setTimeout(() => controller.abort(), 2000);
      

      在這個示例中,我們用最簡單的方式演示了 AbortController 和 AbortSignal 如何配合 fetch() 實現“可中途取消”的網絡請求。

      首先,我們創建了一個 AbortController 實例,它就像任務的“遙控器”,專門用來發出取消的指令。接著,通過 controller.signal 獲取與之綁定的 AbortSignal 對象。這個 signal 會被傳遞給支持取消機制的 API(例如 fetch),作為任務的監聽端。

      fetch 啟動后,它會一直監聽這個 signal 的狀態。如果我們在任務執行中調用了 controller.abort()signal 會立即變為“中止”狀態,fetch 也會立刻終止請求,并拋出一個 AbortError

      在這段代碼里,我們用 setTimeout 模擬了一個“2 秒后取消請求”的場景——這在實際開發中可能對應著請求超時、用戶點擊取消按鈕、或頁面切換等情況。

      這種模式的好處是,你可以用一套統一的方式去管理異步任務的生命周期,不需要依賴特定 API 提供的私有取消方法,從而讓取消邏輯更優雅、更易維護。

      相關細節

      在了解了 AbortController 的核心理念后,接下來我們來看一下該 API 一些細枝末節的知識。

      前面我們聊了 AbortController 的用途和基本用法,但如果你真的要在項目里用得順手,還是得知道它有哪些“開關”和“按鈕”。這一節,我們就來扒一扒它的細節——屬性、方法、甚至是那些看似不起眼的靜態方法。

      1. controller.signal

      這是 AbortController 唯一的屬性,也是它存在的核心意義。
      你可以把它理解為 “傳話的麥克風”——只要控制器這邊說“停”,所有拿著這個 signal 的任務都會聽到。

      • 類型AbortSignal
      • 常用場景:傳給 fetch()ReadableStreamsetTimeout 等支持取消的 API。
      const controller = new AbortController();
      const { signal } = controller;
      
      fetch("/api/data", { signal })
        .then(r => r.json())
        .then(console.log)
        .catch(err => {
          if (err.name === "AbortError") console.log("被取消了");
          else console.error(err);
        });
      
      // 3 秒后取消
      setTimeout(() => controller.abort("timeout"), 3000);
      

      2. controller.abort([reason])

      這是 AbortController 最常用的方法,也是你按下“終止任務”按鈕的地方。

      • 作用:觸發 signalabort 事件,讓關聯的異步任務立刻中止。

      • 可選參數 reason:可以傳一個自定義原因,比如 "Timeout" 或一個 Error 對象,這樣在捕獲時就能知道為什么被中止。

        注意點:調用 controller.abort() 一次就夠了,多次調用沒有額外效果(signal.aborted 會保持 true)。

      const c = new AbortController();
      const s = c.signal;
      
      fetch("/slow", { signal: s }).catch(err => {
        // 在現代瀏覽器/Node 里,err.name === "AbortError"
        // 同時 err.message / s.reason 里能拿到“取消原因”
        if (s.aborted) {
          console.log("已取消,原因:", s.reason); // e.g. "user-cancel" or Error(...)
        }
      });
      
      document.getElementById("cancel").addEventListener("click", () => {
        c.abort("user-cancel");
      });
      

      3. 靜態方法 AbortSignal.abort(reason)

      聽到 AbortSignal.abort() 這個名字,你可能會疑惑:它和實例方法 controller.abort() 到底有什么不同?

      區別在于:AbortSignal.abort() 是一個快捷工廠——直接生成一個已經處于中止狀態的 AbortSignal,免去了你先 new AbortController() 再手動調用 abort() 的步驟。

      它非常適合那種一開始就確定要中止的場景,比如你在寫一個工具函數時,發現條件不滿足,就立即返回一個“無效”的信號,讓后續邏輯立刻停下。

      來看個例子:假設我們有一個支持取消的文件下載工具函數:

      async function downloadFile(url, signal) {
        // 檢查這個 AbortSignal 是否已經處于中止狀態
        // 如果已中止,立即拋出 AbortError,避免發起無意義的請求
        // 這是 AbortSignal 提供的同步檢查方法(現代瀏覽器/Node.js 均支持)
        signal.throwIfAborted();
        const res = await fetch(url, { signal });
        return res.blob();
      }
      

      現在有個需求:

      • 用戶必須登錄才能下載文件
      • 如果未登錄,不僅要阻止下載,還要避免發起任何網絡請求

      AbortSignal.abort() 就能優雅地實現:

      function getDownloadSignal(isLoggedIn) {
        if (!isLoggedIn) {
          // 創建一個“已中止”的 signal,原因是未登錄
          return AbortSignal.abort(new Error("User not logged in"));
        }
        const controller = new AbortController();
        return controller.signal;
      }
      
      // 模擬未登錄
      const signal = getDownloadSignal(false);
      
      // 這里會立刻拋出 AbortError
      downloadFile("/big-file.zip", signal)
        .then(() => console.log("下載完成"))
        .catch(err => {
          if (err.name === "AbortError") {
            console.log("下載被取消:", signal.reason);
          } else {
            console.error(err);
          }
        });
      

      這樣做的好處:

      1. 零浪費:不會發送無意義的請求。
      2. 調用方邏輯一致:依舊通過捕獲 AbortError 處理取消,無需特殊分支。
      3. 寫法簡潔:少了創建控制器再手動 abort() 的步驟。

      4. 靜態方法 AbortController.timeout(ms)

      這是 Node.js 從 v15.4.0 開始加的“便捷版”(瀏覽器端目前大部分不支持,需自行 polyfill)。

      • 作用:創建一個 AbortSignal,并在指定的毫秒數后自動進入中止狀態。
      • 優勢:不用自己寫 setTimeout 再調用 abort(),更簡潔。
      • 典型場景:請求超時控制,比如 fetch(url, { signal: AbortController.timeout(5000) })
      // 5 秒超時:到點自動進入 aborted 狀態
      const signal = AbortSignal.timeout(5000);
      
      fetch("/maybe-slow", { signal })
        .then(r => r.text())
        .then(console.log)
        .catch(err => {
          if (err.name === "AbortError") {
            console.log("超時了");
          } else {
            console.error(err);
          }
        });
      

      總的來講,AbortController 的設計非常簡潔。

      唯一的屬性是 signal,唯一的實例方法是 abort()

      但配合 AbortSignal,它能在異步任務中提供一致、優雅的取消能力。再加上靜態方法的加持,你既能自己掌控中止時機,也能用“一鍵定時取消”快速處理超時場景。

      進階思考

      設想這樣一個場景:你在網頁上點擊了“刪除數據庫記錄”,請求很快發了出去,服務器那邊的 SQL 語句已經開始準備執行。突然,你反悔了,立刻調用 controller.abort()。此時,這個刪除動作真的還能被阻止嗎?

      現實可能會讓你有些失望——大多數情況下,答案是否定的

      AbortController 的取消邏輯,其實只作用在客戶端,它能做到的包括:

      • 讓瀏覽器立即停止發送或接收數據
      • 讓綁定了該信號的異步任務(如 fetch())立刻結束,并拋出 AbortError
      • 丟棄本地的任務結果,不再進行后續處理

      但是,一旦請求已經抵達服務器并開始執行,客戶端的中止信號并不能“遠程撤銷”后端的操作。換句話說,刪除數據庫的 SQL 語句可能已經在運行,你的 abort() 并不能讓它立刻停下來。

      這就像你在餐館點了一份大餐,訂單已經送到廚房,廚師正忙著下鍋。這時你接到一個急事電話,必須馬上離開——雖然你對服務員說“不用了”,但廚房那邊其實已經在做,這道菜并不會因為你離開而自動停下。

      如果真想實現全鏈路取消,就必須有后端的配合——在任務執行過程中檢查取消信號,并在檢測到時主動中止操作。

      因此,AbortController 在前端任務管理中非常實用,但要想讓它變成“全局任務終止按鈕”,前后端需要協同設計取消機制。

      寫在最后

      在現代前后端開發中,異步任務的可控性越來越重要。無論是瀏覽器端的 fetch() 請求、WebSocket 長連接,還是 Node.js 中的文件流、定時器任務,能夠在合適的時機中止它們,意味著更好的資源管理和更流暢的用戶體驗。

      AbortControllerAbortSignal 為我們提供了一套統一且優雅的取消機制——它不依賴具體 API 的私有實現,而是通過“控制器 → 信號”的模式,讓不同類型的異步任務都能用相同的方式進行管理。這不僅降低了心智負擔,也讓取消邏輯更容易抽象成可復用的工具。

      當然,我們也要認識到它的邊界:取消信號只在客戶端生效,并不能直接干預已經在服務器上執行的邏輯。如果需要真正的“全鏈路取消”,就必須在后端配合檢查取消狀態,并在合適的時機主動中止處理。

      因此,在實際項目中,你可以把 AbortController 看作是異步任務的本地總開關

      • 它能幫你優雅地處理請求超時、用戶主動取消、頁面卸載等場景;
      • 它能統一異步任務的生命周期管理方式;
      • 它能減少資源浪費,避免無意義的等待和處理。

      熟練掌握并恰當使用 AbortController,會讓你的異步代碼不僅能“跑起來”,更能“收得住”。


      -EOF-

      posted @ 2025-10-29 14:32  Zhentiw  閱讀(13)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 四虎成人高清永久免费看| 欧美成人黄在线观看| 久久99精品久久久久久9| 亚洲一区二区av高清| 中文午夜乱理片无码| 亚洲av片在线免费观看| 欧美色aⅴ欧美综合色| 亚洲综合精品中文字幕| 国产成人亚洲精品狼色在线| 东京热人妻丝袜无码AV一二三区观| 风间由美性色一区二区三区| 毛片网站在线观看| 午夜福利免费区在线观看| 又爽又黄又无遮掩的免费视频| 人妻系列无码专区69影院| 精品国产成人亚洲午夜福利 | 国产精品天天看天天狠| 国产精品久久久久鬼色| 国产视频一区二区三区四区视频| 99久久成人亚洲精品观看| 久久综合色之久久综合| 亚州中文字幕一区二区| 中文毛片无遮挡高潮免费| 国产精品免费看久久久| 精品人妻日韩中文字幕| 日区中文字幕一区二区| 97欧美精品系列一区二区| 金堂县| 99精品视频九九精品视频| 精品国产成人午夜福利| 又黄又爽又色的少妇毛片| 亚洲aⅴ无码专区在线观看q| 日韩精品一区二区亚洲专区| 野花韩国高清电影| 野外做受三级视频| 国产精品毛片一区二区三| 精品无人乱码一区二区三区的优势| 国产成人午夜在线视频极速观看| 蜜桃成熟色综合久久av| 国产成人精品久久性色av| 亚洲一本二区偷拍精品|