ES6回顧:閉包->(優點:實現工廠函數、記憶化和異步實現)、(應用場景:Promise的then與catch的回調、async/await、柯里化函數)

閉包講解

ES6回顧:閉包->(優點:實現工廠函數、記憶化和異步實現)、(應用場景:Promise的then與catch的回調、async/await、柯里化函數)

以下是與 JavaScript 閉包相關的常見考點整理,結合 Promise、async/await、緩存結果、工廠函數、柯里化等內容,并依據我搜索到的資料進行詳細說明:


1. 閉包(Closure)

  • 定義:由函數及其引用的外部詞法環境變量組成,即使外部函數執行完畢,內部函數仍能訪問這些變量 。
  • 作用
    • 延長外部函數變量的生命周期,使外部可操作內部數據(如模塊化封裝)。
    • 避免全局變量污染,實現私有變量 。
  • 缺點:不當使用會導致內存泄漏(變量無法被回收)。
  • 應用場景
    • 緩存結果:通過閉包保存計算結果,避免重復計算(記憶化函數)。
    • 工廠函數:生成帶有特定配置的函數實例(如計數器生成器)。
    • 柯里化:拆分多參數函數為鏈式單參數調用,依賴閉包保存中間參數 。
    • 異步回調:在事件處理或定時器中保留上下文 。

2. Promise

  • 核心概念
    • 三種狀態:pendingfulfilledrejected,狀態一旦改變不可逆 。
    • 解決回調地獄(Callback Hell),支持鏈式調用 .then().catch()
  • 常用方法
    • Promise.all():所有 Promise 成功時返回結果數組,任一失敗立即拒絕 。
    • Promise.race():首個完成的 Promise 決定最終狀態 。
    • Promise.resolve()/Promise.reject():快速創建成功/失敗的 Promise 。
  • 手寫實現:常考手寫 Promise.allPromise.race 的實現 。

3. async/await

  • 本質:基于 Generator 和 Promise 的語法糖,使異步代碼更接近同步寫法 。
  • 規則
    • async 函數返回 Promise 對象,return 值會被 Promise.resolve() 包裝 。
    • await 后接 Promise,暫停當前函數執行直到 Promise 完成(屬于微任務)。
    • await 只能在 async 函數內使用,否則需通過立即調用異步函數(如 (async () => { ... })())。
  • 錯誤處理:用 try...catch 捕獲 await 后的 Promise 拒絕 。
  • 執行順序await 后的代碼相當于放入 .then() 中,屬于微任務隊列 。
function asyncToGenerator(fn) {// 返回函數return function() {const gen = fn.apply(this, arguments);//生成器// 方法返回一個Promise對象return new Promise((resolve, reject) => {function step(key, arg) {// console.log(arg)let result;try {result = gen[key](arg);//生成器返回數據{value,done:bool}// 移除調試日志以保持輸出整潔} catch (error) {return reject(error);}//如果執行器執行完成if (result.done) {return resolve(result.value);}//如果執行器未完成,將當前結果傳入Promise的resolve方法中,并遞歸調用step方法Promise.resolve(result.value).then(v => step("next", v),e => step("throw", e));}step("next");});};
}// 使用示例(已修復)
const asyncFunction = asyncToGenerator(function* () {// 修正 Promise 的創建方式,使用箭頭函數包裹 resolveconst result = yield new Promise(resolve => setTimeout(() => resolve("result"), 1000));const result1 = yield new Promise(resolve => setTimeout(() => resolve("result2"), 2000));console.log(result, result1); // 輸出: "result" "result2"(3秒后)
});asyncFunction(); // 啟動執行

4. 柯里化(Currying)

  • 定義:將多參數函數轉換為一系列單參數函數鏈式調用的技術,依賴閉包保存中間參數 。
  • 示例
  function add(x) {return function(y) {return x + y;};}add(2)(3); // 5
  • 應用:參數復用、延遲執行、函數組合 。

5. 工廠函數

  • 作用:通過閉包生成具有獨立狀態的函數實例。例如生成獨立的計數器:
  function createCounter() {let count = 0;return function() {return ++count;};}const counter1 = createCounter(); // 獨立作用域
  • 場景:封裝私有變量、實現模塊化 。

6. 閉包與異步編程的結合

  • 事件回調:在閉包中使用 async/await 處理異步邏輯,避免全局變量污染 。
  button.addEventListener('click', () => {(async () => {const data = await fetchData();console.log(data);})();});
  • 定時器:閉包保存定時器狀態,結合 async/await 控制執行流程 。

7. 內存管理

  • 內存泄漏:閉包長期引用外部變量會導致內存無法釋放,需及時解除引用(如手動置 null)。
  • 優化:避免不必要的閉包,或在不需要時清除事件監聽器、定時器等 。

總結

閉包是 JavaScript 的核心概念,與異步編程(Promise/async/await)、函數式編程(柯里化、工廠函數)緊密相關。理解閉包的作用域機制、內存管理,以及與其他特性的結合方式,是應對面試和實際開發的關鍵。


async/await 底層實現解析

async/await 是 JavaScript 中處理異步操作的語法糖,其底層實現基于 PromiseGenerator(生成器) 的協同機制。通過分析資料中的代碼轉換、設計原理和規范定義,其核心實現邏輯可拆解如下:


一、核心依賴:Promise 與 Generator 的協作
  1. Promise 的基礎作用
    async/await 的異步控制完全依賴于 Promise 的鏈式調用。每個 await 表達式本質上會創建一個 Promise,并將后續代碼包裝到 .then() 中等待執行。例如:

    async function foo() {const result = await somePromise; // 等價于 somePromise.then(result => {...})
    }
    

    這種設計使得異步操作的 狀態管理錯誤傳播 能夠通過 Promise 鏈式結構實現。

  2. Generator 的流程控制
    Generator 函數通過 yield 關鍵字暫停執行,并通過迭代器(Iterator)手動恢復。async/await 利用這一特性,將異步代碼的 暫停-恢復機制 轉化為生成器函數的 yield 操作。例如,以下代碼:

    async function a() {const res = await asyncTask();
    }
    

    會被 Babel 轉換為使用 Generator 的代碼:

    function a() {return __awaiter(this, void 0, void 0, function* () {const res = yield asyncTask();});
    }
    

    這里的 yield 替代了 await,而 __awaiter 函數負責管理生成器的迭代。


二、轉換邏輯:代碼降級與執行器封裝

通過 Babel/TypeScript 等工具的代碼轉換,async/await 的實現可拆解為以下步驟:

  1. 生成器函數包裝
    async 函數被轉換為生成器函數,await 被替換為 yield。例如:

    // 原始代碼
    async function fetchData() {const data = await fetch(url);return data;
    }// 轉換后代碼(簡化)
    function fetchData() {return __awaiter(this, function* () {const data = yield fetch(url);return data;});
    }
    
  2. 執行器函數(如 __awaiter)的作用
    執行器負責驅動生成器的迭代,并處理 Promise 的鏈式調用。其核心邏輯如下:

    • 將生成器的每個 yield 值包裝為 Promise。
    • 通過 generator.next(value) 將 Promise 的結果傳遞回生成器。
    • 捕獲錯誤并通過 generator.throw(error) 拋出異常。
    function __awaiter(generator) {return new Promise((resolve, reject) => {function step(result) {if (result.done) {resolve(result.value);} else {Promise.resolve(result.value).then(value => step(generator.next(value)), // 傳遞結果并繼續迭代error => step(generator.throw(error)) // 拋出錯誤);}}step(generator.next());});
    }
    

    此過程實現了 自動迭代錯誤冒泡,使代碼看似同步執行。


三、執行順序與事件循環的關聯
  1. 微任務隊列的調度
    await 后的代碼會被包裝為微任務(Microtask),在 Promise 解決后加入微任務隊列。例如:

    async function demo() {console.log(1);await Promise.resolve();console.log(2); // 相當于 Promise.resolve().then(() => console.log(2))
    }
    demo();
    console.log(3);
    // 輸出順序:1 → 3 → 2
    

    這種機制確保了異步代碼的執行不會阻塞主線程。

  2. 協程(Coroutine)模型的實現
    async/await 通過生成器和 Promise 模擬了協程的 掛起-恢復 行為:

    • 掛起:在 await 處暫停生成器,釋放主線程。
    • 恢復:當 Promise 解決后,通過執行器繼續生成器的迭代。

四、錯誤處理機制的實現
  1. try/catch 的轉換
    async 函數中的 try/catch 會被轉換為 Promise 的 .catch() 鏈。例如:

    async function foo() {try {await somePromise();} catch (err) {handleError(err);}
    }
    

    轉換后邏輯:

    function* foo() {try {const result = yield somePromise();} catch (err) {handleError(err);}
    }
    

    執行器在生成器拋出錯誤時觸發 reject

  2. 未捕獲異常的傳播
    若未使用 try/catch,錯誤會通過 Promise 鏈冒泡到頂層,觸發 unhandledrejection 事件。


五、性能與優化考量
  1. 生成器與 Promise 的開銷
    async/await 相比原生 Promise 鏈會引入額外開銷(如生成器對象的創建),但在現代引擎中差異可忽略。

  2. 并發的實現方式
    需顯式使用 Promise.all() 實現并行,避免順序等待:

    async function parallel() {const [a, b] = await Promise.all([task1(), task2()]); // 并行執行
    }
    

    若直接順序 await,會導致任務串行執行。


總結:async/await 的架構設計

層級實現機制作用
語法層async/await 關鍵字提供同步代碼風格的異步寫法
轉換層Babel/TypeScript 代碼降級將 async/await 轉為 Generator + Promise
運行時層生成器迭代器 + Promise 鏈管理暫停/恢復、錯誤傳播
事件循環層微任務隊列調度確保異步代碼非阻塞執行

通過多層抽象,async/await 將復雜的異步流程控制簡化為直觀的同步式代碼,同時保持與 Promise 的完全兼容性。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/73288.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/73288.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/73288.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

OpenMCU(三):STM32F103 FreeRTOS移植

概述 本文主要描述了STM32F103移植FreeRTOS的簡要步驟。移植描述過程中,忽略了Keil軟件的部分使用技巧。默認讀者熟練使用Keil軟件。本文的描述是基于OpenMCU_RTOS這個工程,該工程已經下載放好了移植STM32F103 FreeRTOS的所有文件 OpenMCU_RTOS工程的愿景…

生成對抗網絡(GAN)原理與應用

目錄 一、引言 二、GAN的基本原理 (一)生成器(Generator)的工作機制 (二)判別器(Discriminator)的工作機制 (三)對抗訓練的過程 三、GAN在AIGC生圖中的應…

STM32 內置的通訊協議

數據是以幀為單位發的 USART和UART的區別就是有沒有同步功能 同步是兩端設備有時鐘連接,異步是沒時鐘連接,靠約定號的頻率(波特率)接收發送數據 RTS和CTS是用來給外界發送已“可接收”或“可發送”信號的,一般用不到…

ES 使用geo point 查詢離目標地址最近的數據

需求描述:項目中需要通過經緯度坐標查詢目標地所在的行政區。 解決思路大致有種,使用es和mysql分別查詢。 1、使用es進行查詢 將帶有經緯度坐標的省市區數據存入es中,mappings字段使用geo point類型,索引及查詢dsl如下。 geo p…

Appium等待機制--強制等待、隱式等待、顯式等待

書接上回,Appium高級操作--其他操作-CSDN博客文章瀏覽閱讀182次,點贊6次,收藏7次。書接上回Appium高級操作--從源碼角度解析--模擬復雜手勢操作-CSDN博客。https://blog.csdn.net/fantasy_4/article/details/146162851主要講解了Appium的一些…

【架構藝術】Go語言微服務monorepo的代碼架構設計

近期因為項目架構升級原因,筆者著手調研一些go項目monorepo的代碼架構設計,目標是長期把既有微服務項目重要的部分都轉移到monorepo上面,讓代碼更容易維護,協作開發更加方便。雖然經驗不多,但既然有了初步的調研&#…

深入解析 JVM —— 從基礎概念到實戰調優的全鏈路學習指南

文章目錄 一、為什么要學習 JVM?1. 面試必備與技能提升2. 性能優化與問題診斷3. 編寫高質量代碼 二、JVM 基礎概念與體系結構1. JVM 簡介2. JDK、JRE 與 JVM 三、JVM 內存模型1. 線程私有區2. 線程共享區 四、類加載機制與雙親委派1. 類加載過程2. 雙親委派模型3. 動…

前端及后端實現csv文件下載功能

方法一、 前端內容: const url window.URL.createObjectURL(new Blob([res.data])); const link document.createElement(a); link.href url; const fileNameDateTime getFormattedDateTime(); const filename "用戶提現列表"fileNameDateTime.csv…

QT中委托QStyledItemDelegate的使用

目錄 一、子類化委托 二、委托方法實現 1)createEditor 2)setEditorData 3)setModelData 4)updateEditorGeometry 三、委托使用 四、總結 Qt的數據容器控件采用模型/視圖(model/view)架構設計。模型用于存放控件的數據,視圖則用于顯示編輯數據,而委托則是…

OpenCV實現視頻背景提取

在計算機視覺領域,背景減除(Background Subtraction)是一種常用的技術,用于從視頻序列中提取前景對象。 背景減除的核心思想是通過建模背景,然后將當前幀與背景模型進行比較,從而分離出前景對象。 OpenCV…

NFS實驗配置筆記

NFS NFS服務 nfs,最早是Sun這家公司所發展出來的,它最大的功能就是可以透過網絡,讓不同的機器,不同的操作系統,進行實現文檔的共享。所以你可以簡單的將他看做是文件服務器。 實驗準備 ①先準備一個服務器端的操作…

C語言【數據結構】:理解什么是數據結構和算法(啟航)

引言 啟航篇,理解什么是數據結構和算法 在 C 語言編程領域,數據結構和算法是兩個核心且緊密相關的概念 一、數據結構 定義 數據結構是指相互之間存在一種或多種特定關系的數據元素的集合(比如數組),它是組織和存儲數…

Vue.js 3 的設計思路:從聲明式UI到高效渲染機制

目錄 一、聲明式UI與虛擬DOM的靈活性 二、渲染器:虛擬DOM到真實DOM的橋梁 三、組件的本質與實現 四、編譯與運行時的協同優化 五、性能與可維護性的權衡 總結 Vue.js 3 作為新一代前端框架,其設計理念在聲明式UI描述、虛擬DOM優化、組件化架構…

深度學習|MAE技術全景圖:自監督學習的“掩碼魔法“如何重塑AI基礎

一、引言:深度學習的困境與自監督的曙光 深度學習(Deep Learning)無疑是當今人工智能領域基礎中的基礎。從圖像識別到自然語言處理(NLP),它在無數任務中展現了卓越性能。例如,在安防監控中&…

深度學習正則化技術之權重衰減法、暫退法(通俗易懂版)

一、影響模型泛性的因素有?什么是正則化技術?有什么用? 通常,影響模型泛化能力的因素有: 可調節參數的個數:可調節的參數過少,會造成模型過于簡單,欠擬合;過多&#xf…

爬蟲逆向:Unicorn 詳細使用指南

文章目錄 1. Unicorn 介紹1.1 Unicorn 的特點1.2 Unicorn功能2. 安裝 Unicorn2.1 安裝 Python 綁定2.2 安裝 Unicorn 核心庫3. Unicorn 的基本使用3.1 初始化模擬器3.2 映射內存3.3 寫入代碼3.4 設置寄存器3.5 執行代碼3.6 讀取寄存器4. Unicorn 的高級功能4.1 鉤子函數4.2 異常…

【SpringBoot】實現登錄功能

在上一篇博客中,我們講解了注冊頁面的實現。在此基礎上會跳轉到登錄頁面,今天給大家帶來的是使用 SpringBoot,MyBatis,Html,CSS,JavaScript,前后端交互實現一個登錄功能。 目錄 一、效果 二、…

【小白向】Ubuntu|VMware 新建虛擬機后打開 SSH 服務、在主機上安裝vscode并連接、配置 git 的 ssh

常常有人問VMware-Tools裝了也復制粘貼不了怎么辦,這個東西影響因素太多了,具體解決辦法你們可以參考一下:【經驗】VMware|虛擬機只能使用鼠標無法使用鍵盤、裝不了或裝了VMware-Tools無法復制粘貼的可能解決辦法_增強型鍵盤驅動程…

mingw工具源碼編譯

ming-w64 mingw編譯生成的庫,需要mingw的lib文件支持。 https://github.com/mingw-w64/mingw-w64 使用msys2的bash git checkout v8.0.3 ./configure --disable-dependency-tracking --targetx86_64-w64-mingw32 mingw32-make.exe -j4 修改makefile中的make 改成mi…

LSTM方法實踐——基于LSTM的汽車銷量時序建模與預測分析

Hi,大家好,我是半畝花海。本實驗基于汽車銷量時序數據,使用LSTM網絡(長短期記憶網絡)構建時間序列預測模型。通過數據預處理、模型訓練與評估等完整流程,驗證LSTM在短期時序預測中的有效性。 目錄 一、實驗…