亚洲乱色熟女一区二区三区丝袜,天堂√中文最新版在线,亚洲精品乱码久久久久久蜜桃图片,香蕉久久久久久av成人,欧美丰满熟妇bbb久久久

LOGO OA教程 ERP教程 模切知識交流 PMS教程 CRM教程 開發(fā)文檔 其他文檔  
 
網(wǎng)站管理員

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

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


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

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


一、Ajax 的本質(zhì):異步通信的基石

1.1 什么是 Ajax?

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

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


1.2 手寫 Ajax 請求

步驟一:創(chuàng)建 XMLHttpRequest 對象

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

步驟二:發(fā)送 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("成功獲取天氣數(shù)據(jù):", JSON.parse(xhr.responseText));    } else if (xhr.readyState === 4) {      console.error("請求失敗,狀態(tài)碼:", xhr.status);    }  };  xhr.send(); } // 調(diào)用示例 getWeather("北京");

代碼解析:

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

1.3 手寫 Ajax 的痛點

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

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

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


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

2.1 Promise 的核心思想

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

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


2.2 手寫 Promise 的核心邏輯

步驟一:定義 Promise 的狀態(tài)

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

代碼解析:

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

2.3 手寫 Promise 的優(yōu)化:鏈式調(diào)用

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 {        // 異步情況下,先將回調(diào)存入隊列        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;  } }

代碼解析:

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

三、結(jié)合 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(`請求失敗,狀態(tài)碼: ${xhr.status}`);        }      }    };    xhr.send();  }); } // 使用示例 getWeather("北京")  .then((data) => {    console.log("成功獲取天氣數(shù)據(jù):", data);    return getWeather("上海"); // 鏈式調(diào)用  })  .then((data) => {    console.log("成功獲取上海天氣數(shù)據(jù):", data);  })  .catch((error) => {    console.error("請求失敗:", error);  });

代碼解析:

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

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

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

四、Promise 的底層原理詳解

4.1 Promise 的狀態(tài)管理

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

關(guān)鍵點:狀態(tài)一旦改變,不可逆;Promise 只能有一個最終結(jié)果。


4.2 微任務隊列與事件循環(huán)

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

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

生活類比:

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

4.3 鏈式調(diào)用的實現(xiàn)原理

每個 .then() 返回一個新的 Promise 實例,形成鏈式結(jié)構(gòu)。通過遞歸調(diào)用 then,可以實現(xiàn)異步操作的串聯(lián)。

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  });

五、總結(jié):從“手寫”到“理解”

5.1 核心收獲

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

5.2 實際應用建議

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

六、結(jié)語

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


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