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

手寫 Ajax 與 Promise:從底層原理到實(shí)際應(yīng)用

liguoquan
2025年7月9日 15:33 本文熱度 552
:手寫 Ajax 與 Promise:從底層原理到實(shí)際應(yīng)用


手寫 Ajax 與 Promise:從底層原理到實(shí)際應(yīng)用

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


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

1.1 什么是 Ajax?

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

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


1.2 手寫 Ajax 請(qǐng)求

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

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

步驟二:發(fā)送 GET 請(qǐng)求

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("請(qǐng)求失敗,狀態(tài)碼:", xhr.status);    }  };  xhr.send(); } // 調(diào)用示例 getWeather("北京");

代碼解析:

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

1.3 手寫 Ajax 的痛點(diǎn)

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

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

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


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

2.1 Promise 的核心思想

Promise 是一種異步編程的容器,它將異步操作的結(jié)果(成功或失?。┓庋b成一個(gè)對(duì)象,通過鏈?zhǔn)秸{(diào)用和統(tǒng)一的接口管理異步流程。

生活類比
Promise 像是一張“承諾書”。你告訴服務(wù)器:“我需要數(shù)據(jù)”,服務(wù)器承諾在某個(gè)時(shí)間點(diǎn)給你結(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)隊(duì)列    this.onRejectedCallbacks = []; // 失敗回調(diào)隊(duì)列    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); // 捕獲同步錯(cuò)誤    }  }  then(onFulfilled, onRejected) {    if (this.status === "fulfilled") {      onFulfilled(this.value);    } else if (this.status === "rejected") {      onRejected(this.reason);    } else {      // 異步情況下,先將回調(diào)存入隊(duì)列      this.onFulfilledCallbacks.push(() => onFulfilled(this.value));      this.onRejectedCallbacks.push(() => onRejected(this.reason));    }  } }

代碼解析:

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

2.3 手寫 Promise 的優(yōu)化:鏈?zhǔn)秸{(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)存入隊(duì)列        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;  } }

代碼解析:

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

三、結(jié)合 Ajax 的 Promise 封裝

3.1 用 Promise 封裝 Ajax 請(qǐng)求

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

代碼解析:

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

3.2 生活類比:從“點(diǎn)外賣”到“智能配送”

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

四、Promise 的底層原理詳解

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

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

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


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

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

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

生活類比:

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

4.3 鏈?zhǔn)秸{(diào)用的實(shí)現(xiàn)原理

每個(gè) .then() 返回一個(gè)新的 Promise 實(shí)例,形成鏈?zhǔn)浇Y(jié)構(gòu)。通過遞歸調(diào)用 then,可以實(shí)現(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 實(shí)現(xiàn)異步通信,但存在代碼冗余和回調(diào)地獄的問題。
  2. Promise 的優(yōu)勢(shì):通過狀態(tài)管理和鏈?zhǔn)秸{(diào)用,簡(jiǎn)化異步代碼,提升可維護(hù)性。
  3. 底層原理:Promise 通過微任務(wù)隊(duì)列和回調(diào)隊(duì)列管理異步流程,狀態(tài)不可逆且只能有一個(gè)結(jié)果。

5.2 實(shí)際應(yīng)用建議

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

六、結(jié)語

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


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

黄频国产免费高清视频,久久不卡精品中文字幕一区,激情五月天AV电影在线观看,欧美国产韩国日本一区二区
色偷偷91综合久久噜噜噜 | 中文字幕日韩综合网 | 亚洲综合在线精品 | 日本一本久道视频 | 亚洲欧美另类中文字幕在线 | 中文字幕乱码亚洲影视 |