狠狠色丁香婷婷综合尤物/久久精品综合一区二区三区/中国有色金属学报/国产日韩欧美在线观看 - 国产一区二区三区四区五区tv

LOGO OA教程 ERP教程 模切知識交流 PMS教程 CRM教程 開發文檔 其他文檔  
 
網站管理員

手寫 Ajax 與 Promise:從底層原理到實際應用

liguoquan
2025年7月9日 15:33 本文熱度 194
:手寫 Ajax 與 Promise:從底層原理到實際應用


手寫 Ajax 與 Promise:從底層原理到實際應用

?在前端開發中,異步請求Promise是繞不開的核心知識點。無論是獲取數據、提交表單,還是處理復雜的業務邏輯,我們都需要與異步操作打交道。本文將通過手寫 Ajax 請求和解析 Promise 的底層原理,結合生活中的實際案例,帶你深入理解這些技術的本質。


一、Ajax 的本質:異步通信的基石

1.1 什么是 Ajax?

Ajax(Asynchronous JavaScript and XML)是一種通過 JavaScript 與服務器進行異步通信的技術。它允許頁面在不刷新的情況下動態更新數據,極大提升了用戶體驗。

生活類比
想象你在點外賣。你下單后,不需要一直盯著手機等外賣送到,而是繼續做其他事情。外賣送達時,系統會通知你。這個“異步等待”的過程,就是 Ajax 的核心思想。


1.2 手寫 Ajax 請求

步驟一:創建 XMLHttpRequest 對象

function createAjaxRequest() {  if (window.XMLHttpRequest) {    return new XMLHttpRequest(); // 現代瀏覽器  } else {    return new ActiveXObject("Microsoft.XMLHTTP"); // 兼容 IE6-IE11  } }

步驟二:發送 GET 請求

function getWeather(city) {  const xhr = createAjaxRequest();  xhr.open("GET", `https://api.example.com/weather?city=${city}`, true);  xhr.onreadystatechange = function () {    if (xhr.readyState === 4 && xhr.status === 200) {      console.log("成功獲取天氣數據:", JSON.parse(xhr.responseText));    } else if (xhr.readyState === 4) {      console.error("請求失敗,狀態碼:", xhr.status);    }  };  xhr.send(); } // 調用示例 getWeather("北京");

代碼解析:

  • open():初始化請求,指定方法(GET/POST)、URL 和是否異步。
  • onreadystatechange:監聽請求狀態變化。
  • send():發送請求。

1.3 手寫 Ajax 的痛點

上述代碼雖然能工作,但存在以下問題:

  1. 重復代碼:每次請求都要手動處理狀態判斷和錯誤處理。
  2. 回調地獄:多個異步操作嵌套會導致代碼難以維護。
  3. 缺乏統一接口:不同瀏覽器的兼容性處理復雜。

生活類比
這就像每次點外賣都要自己跑廚房、打包、配送。效率低且容易出錯。


二、Promise 的底層原理:優雅處理異步的“樂高積木”

2.1 Promise 的核心思想

Promise 是一種異步編程的容器,它將異步操作的結果(成功或失敗)封裝成一個對象,通過鏈式調用和統一的接口管理異步流程。

生活類比
Promise 像是一張“承諾書”。你告訴服務器:“我需要數據”,服務器承諾在某個時間點給你結果。無論成功還是失敗,你都可以通過 .then() 或 .catch() 處理。


2.2 手寫 Promise 的核心邏輯

步驟一:定義 Promise 的狀態

class MyPromise {  constructor(executor) {    this.status = "pending"; // 初始狀態    this.value = undefined; // 成功值    this.reason = undefined; // 失敗原因    this.onFulfilledCallbacks = []; // 成功回調隊列    this.onRejectedCallbacks = []; // 失敗回調隊列    const resolve = (value) => {      if (this.status === "pending") {        this.status = "fulfilled";        this.value = value;        // 觸發所有成功回調        this.onFulfilledCallbacks.forEach((fn) => fn());      }    };    const reject = (reason) => {      if (this.status === "pending") {        this.status = "rejected";        this.reason = reason;        // 觸發所有失敗回調        this.onRejectedCallbacks.forEach((fn) => fn());      }    };    try {      executor(resolve, reject); // 執行用戶傳入的函數    } catch (error) {      reject(error); // 捕獲同步錯誤    }  }  then(onFulfilled, onRejected) {    if (this.status === "fulfilled") {      onFulfilled(this.value);    } else if (this.status === "rejected") {      onRejected(this.reason);    } else {      // 異步情況下,先將回調存入隊列      this.onFulfilledCallbacks.push(() => onFulfilled(this.value));      this.onRejectedCallbacks.push(() => onRejected(this.reason));    }  } }

代碼解析:

  • 狀態管理:Promise 有三種狀態(pendingfulfilledrejected),狀態一旦改變不可逆。
  • 回調隊列:當 Promise 處于 pending 狀態時,先將回調函數暫存,等到狀態改變后再執行。
  • 錯誤處理:通過 try-catch 捕獲同步錯誤,避免程序崩潰。

2.3 手寫 Promise 的優化:鏈式調用

class MyPromise {  // ... 上述代碼省略 ...  then(onFulfilled, onRejected) {    const promise2 = new MyPromise((resolve, reject) => {      if (this.status === "fulfilled") {        setTimeout(() => {          try {            const x = onFulfilled(this.value);            resolve(x); // 返回新 Promise          } catch (e) {            reject(e);          }        }, 0);      } else if (this.status === "rejected") {        setTimeout(() => {          try {            const x = onRejected(this.reason);            resolve(x);          } catch (e) {            reject(e);          }        }, 0);      } else {        // 異步情況下,先將回調存入隊列        this.onFulfilledCallbacks.push(() => {          setTimeout(() => {            try {              const x = onFulfilled(this.value);              resolve(x);            } catch (e) {              reject(e);            }          }, 0);        });        this.onRejectedCallbacks.push(() => {          setTimeout(() => {            try {              const x = onRejected(this.reason);              resolve(x);            } catch (e) {              reject(e);            }          }, 0);        });      }    });    return promise2;  } }

代碼解析:

  • 鏈式調用:每個 .then() 返回一個新的 Promise 實例,實現鏈式調用。
  • 微任務隊列:使用 setTimeout(fn, 0) 將回調放入微任務隊列,確保異步執行順序正確。

三、結合 Ajax 的 Promise 封裝

3.1 用 Promise 封裝 Ajax 請求

function getWeather(city) {  return new MyPromise((resolve, reject) => {    const xhr = createAjaxRequest();    xhr.open("GET", `https://api.example.com/weather?city=${city}`, true);    xhr.onreadystatechange = function () {      if (xhr.readyState === 4) {        if (xhr.status === 200) {          resolve(JSON.parse(xhr.responseText));        } else {          reject(`請求失敗,狀態碼: ${xhr.status}`);        }      }    };    xhr.send();  }); } // 使用示例 getWeather("北京")  .then((data) => {    console.log("成功獲取天氣數據:", data);    return getWeather("上海"); // 鏈式調用  })  .then((data) => {    console.log("成功獲取上海天氣數據:", data);  })  .catch((error) => {    console.error("請求失敗:", error);  });

代碼解析:

  • 封裝邏輯:將 Ajax 請求封裝為 Promise,統一處理成功和失敗。
  • 鏈式調用:通過 .then() 實現多個異步操作的串聯。
  • 錯誤捕獲:通過 .catch() 統一處理所有錯誤,避免嵌套回調。

3.2 生活類比:從“點外賣”到“智能配送”

  • 未使用 Promise:每次點外賣都要手動查看配送狀態,代碼嵌套復雜。
  • 使用 Promise:系統自動通知你配送結果,你可以專注于其他事情,無需頻繁檢查。

四、Promise 的底層原理詳解

4.1 Promise 的狀態管理

狀態描述
pending初始狀態,既不是成功也不是失敗
fulfilled操作成功完成
rejected操作失敗

關鍵點:狀態一旦改變,不可逆;Promise 只能有一個最終結果。


4.2 微任務隊列與事件循環

Promise 的 .then() 和 .catch() 方法會在微任務隊列中執行,優先級高于宏任務(如 setTimeout)。這是 Promise 實現異步流程控制的關鍵。

console.log("Start"); // 同步代碼 new MyPromise((resolve) => {  console.log("Promise executor"); // 同步代碼  resolve(); }).then(() => {  console.log("Promise then"); // 微任務 }); setTimeout(() => {  console.log("Timeout"); // 宏任務 }, 0); console.log("End"); // 同步代碼 // 輸出順序: // Start // Promise executor // End // Promise then // Timeout

生活類比:

  • 同步代碼:像排隊點餐,必須等前面的人處理完才能輪到你。
  • 微任務:像餐廳的快速通道,優先處理。
  • 宏任務:像普通排隊,需等待其他任務完成。

4.3 鏈式調用的實現原理

每個 .then() 返回一個新的 Promise 實例,形成鏈式結構。通過遞歸調用 then,可以實現異步操作的串聯。

new MyPromise((resolve) => {  resolve(1); })  .then((value) => {    console.log(value); // 1    return value + 1;  })  .then((value) => {    console.log(value); // 2    return value + 1;  })  .then((value) => {    console.log(value); // 3  });

五、總結:從“手寫”到“理解”

5.1 核心收獲

  1. Ajax 的本質:通過 XMLHttpRequest 實現異步通信,但存在代碼冗余和回調地獄的問題。
  2. Promise 的優勢:通過狀態管理和鏈式調用,簡化異步代碼,提升可維護性。
  3. 底層原理:Promise 通過微任務隊列和回調隊列管理異步流程,狀態不可逆且只能有一個結果。

5.2 實際應用建議

  • 封裝 Ajax:將重復邏輯抽離為 Promise,提高代碼復用性。
  • 避免回調地獄:使用 .then() 和 .catch() 替代嵌套回調。
  • 理解事件循環:掌握微任務和宏任務的執行順序,避免異步邏輯錯誤。

六、結語

手寫 Ajax 和 Promise 不僅是面試高頻考點,更是深入理解前端異步編程的關鍵。通過本文的實踐和解析,希望你能真正掌握這些技術的核心思想,并在實際項目中靈活運用。如果覺得內容對你有幫助,歡迎點贊、收藏,或分享給更多開發者!


該文章在 2025/7/9 15:33:45 編輯過
關鍵字查詢
相關文章
正在查詢...
點晴ERP是一款針對中小制造業的專業生產管理軟件系統,系統成熟度和易用性得到了國內大量中小企業的青睞。
點晴PMS碼頭管理系統主要針對港口碼頭集裝箱與散貨日常運作、調度、堆場、車隊、財務費用、相關報表等業務管理,結合碼頭的業務特點,圍繞調度、堆場作業而開發的。集技術的先進性、管理的有效性于一體,是物流碼頭及其他港口類企業的高效ERP管理信息系統。
點晴WMS倉儲管理系統提供了貨物產品管理,銷售管理,采購管理,倉儲管理,倉庫管理,保質期管理,貨位管理,庫位管理,生產管理,WMS管理系統,標簽打印,條形碼,二維碼管理,批號管理軟件。
點晴免費OA是一款軟件和通用服務都免費,不限功能、不限時間、不限用戶的免費OA協同辦公管理系統。
Copyright 2010-2025 ClickSun All Rights Reserved