消除異步的傳染性

消除異步的傳染性

https://juejin.cn/post/7206297124940988472?searchId=202502111004349BF73B2AD669425A2367

使用拋出錯(cuò)誤 執(zhí)行多次的方式 拋出錯(cuò)誤 中斷錯(cuò)誤 等待完成 緩存結(jié)果 然后再次執(zhí)行 優(yōu)先獲取緩存結(jié)果 正常則 通過執(zhí)行2次的形式 來最終實(shí)現(xiàn)消除異步的傳染性

deepseek的答案

在 JavaScript 中,異步操作的“傳染性”指的是當(dāng)一個(gè)函數(shù)變?yōu)楫惒胶?,其調(diào)用鏈上的所有函數(shù)也必須處理異步性(如返回 Promise 或使用 async/await)。要減少這種傳染性,可以通過以下方法實(shí)現(xiàn)同步風(fēng)格的異步代碼:


方法 1:生成器函數(shù) + 自動(dòng)執(zhí)行器

通過生成器(Generator)和 yield 暫停執(zhí)行,配合自動(dòng)執(zhí)行器處理異步操作,使得代碼看起來像同步風(fēng)格。

示例代碼

// 自動(dòng)執(zhí)行器
function runGenerator(generator) {
  const iterator = generator();
  function handle(iteration) {
    if (iteration.done) return Promise.resolve(iteration.value);
    return Promise.resolve(iteration.value)
      .then((res) => handle(iterator.next(res)))
      .catch((err) => handle(iterator.throw(err)));
  }
  return handle(iterator.next());
}

// 示例異步函數(shù)
function fetchData() {
  return fetch("https://api.example.com/data").then((res) => res.json());
}

// 生成器函數(shù)(看似同步的代碼)
function* main() {
  try {
    const data = yield fetchData(); // yield 暫停,等待異步操作完成
    console.log("Data received:", data);
  } catch (error) {
    console.error("Error:", error);
  }
}

// 執(zhí)行
runGenerator(main);

關(guān)鍵點(diǎn)

  • 生成器函數(shù) main 使用 yield 暫停,等待異步操作結(jié)果。
  • 執(zhí)行器 runGenerator 自動(dòng)處理 Promise,將結(jié)果傳回生成器。
  • 調(diào)用鏈不強(qiáng)制要求 async/await,但執(zhí)行器返回 Promise,頂層仍需處理異步。

方法 2:Async/await 隔離

將異步操作封裝在獨(dú)立模塊中,在程序初始化時(shí)預(yù)加載數(shù)據(jù),后續(xù)直接使用同步數(shù)據(jù)。

示例代碼

// 數(shù)據(jù)緩存模塊
let cachedData = null;

async function initialize() {
  cachedData = await fetch("https://api.example.com/data").then((res) => res.json());
}

// 初始化時(shí)預(yù)加載數(shù)據(jù)
initialize().catch(console.error);

// 后續(xù)使用同步數(shù)據(jù)(假設(shè)數(shù)據(jù)已加載)
function getData() {
  if (!cachedData) throw new Error("Data not loaded");
  return cachedData;
}

// 業(yè)務(wù)代碼
function processData() {
  const data = getData(); // 同步調(diào)用
  console.log("Processing:", data);
}

關(guān)鍵點(diǎn)

  • 異步操作集中在初始化階段,后續(xù)代碼直接訪問緩存數(shù)據(jù)。
  • 需確保數(shù)據(jù)加載完成后再調(diào)用同步方法,否則可能出錯(cuò)。

方法 3:React Suspense(框架特定方案)

在 React 中,通過 Suspense 組件處理異步渲染,使組件代碼保持同步風(fēng)格。

示例代碼

// 封裝異步資源的函數(shù)
function fetchResource(promise) {
  let status = "pending";
  let result;
  const suspender = promise.then(
    (res) => {
      status = "success";
      result = res;
    },
    (err) => {
      status = "error";
      result = err;
    }
  );
  return {
    read() {
      if (status === "pending") throw suspender;
      if (status === "error") throw result;
      return result;
    },
  };
}

// 在組件中使用
const resource = fetchResource(fetch("https://api.example.com/data").then((r) => r.json()));

function MyComponent() {
  const data = resource.read(); // 同步調(diào)用,但需要 Suspense 支持
  return <div>{data}</div>;
}

// 在根組件包裹 Suspense
function App() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <MyComponent />
    </Suspense>
  );
}

關(guān)鍵點(diǎn)

  • resource.read() 在數(shù)據(jù)未就緒時(shí)拋出 Promise,由 Suspense 捕獲并顯示加載狀態(tài)。
  • 組件代碼無需處理異步邏輯,但需依賴 React 框架。

總結(jié)

  1. 生成器 + 執(zhí)行器:用同步風(fēng)格寫異步代碼,但需依賴執(zhí)行器。
  2. 預(yù)加載 + 緩存:將異步操作提前完成,后續(xù)直接訪問數(shù)據(jù)。
  3. 框架方案:如 React Suspense,在特定生態(tài)中隱藏異步細(xì)節(jié)。

JavaScript 無法完全消除異步傳染性,但通過設(shè)計(jì)模式或工具可減少其對(duì)代碼結(jié)構(gòu)的影響。選擇方案時(shí)需權(quán)衡代碼復(fù)雜度、框架支持和實(shí)際需求。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容