消除异步的传染性

消除异步的传染性

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

使用抛出错误 执行多次的方式 抛出错误 中断错误 等待完成 缓存结果 然后再次执行 优先获取缓存结果 正常则 通过执行2次的形式 来最终实现消除异步的传染性

deepseek的答案

在 JavaScript 中,异步操作的“传染性”指的是当一个函数变为异步后,其调用链上的所有函数也必须处理异步性(如返回 Promise 或使用 async/await)。要减少这种传染性,可以通过以下方法实现同步风格的异步代码:


方法 1:生成器函数 + 自动执行器

通过生成器(Generator)和 yield 暂停执行,配合自动执行器处理异步操作,使得代码看起来像同步风格。

示例代码

// 自动执行器
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());
}

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

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

// 执行
runGenerator(main);

关键点

  • 生成器函数 main 使用 yield 暂停,等待异步操作结果。
  • 执行器 runGenerator 自动处理 Promise,将结果传回生成器。
  • 调用链不强制要求 async/await,但执行器返回 Promise,顶层仍需处理异步。

方法 2:Async/await 隔离

将异步操作封装在独立模块中,在程序初始化时预加载数据,后续直接使用同步数据。

示例代码

// 数据缓存模块
let cachedData = null;

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

// 初始化时预加载数据
initialize().catch(console.error);

// 后续使用同步数据(假设数据已加载)
function getData() {
  if (!cachedData) throw new Error("Data not loaded");
  return cachedData;
}

// 业务代码
function processData() {
  const data = getData(); // 同步调用
  console.log("Processing:", data);
}

关键点

  • 异步操作集中在初始化阶段,后续代码直接访问缓存数据。
  • 需确保数据加载完成后再调用同步方法,否则可能出错。

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

在 React 中,通过 Suspense 组件处理异步渲染,使组件代码保持同步风格。

示例代码

// 封装异步资源的函数
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(); // 同步调用,但需要 Suspense 支持
  return <div>{data}</div>;
}

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

关键点

  • resource.read() 在数据未就绪时抛出 Promise,由 Suspense 捕获并显示加载状态。
  • 组件代码无需处理异步逻辑,但需依赖 React 框架。

总结

  1. 生成器 + 执行器:用同步风格写异步代码,但需依赖执行器。
  2. 预加载 + 缓存:将异步操作提前完成,后续直接访问数据。
  3. 框架方案:如 React Suspense,在特定生态中隐藏异步细节。

JavaScript 无法完全消除异步传染性,但通过设计模式或工具可减少其对代码结构的影响。选择方案时需权衡代码复杂度、框架支持和实际需求。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,002评论 6 509
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,777评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,341评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,085评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,110评论 6 395
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,868评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,528评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,422评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,938评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,067评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,199评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,877评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,540评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,079评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,192评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,514评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,190评论 2 357

推荐阅读更多精彩内容