当前位置: 首页 > news >正文

如何消除异步 async 的传染性呢?

1. 问题现象

有一段代码如下:由于在 getUser 函数中调用了 fetch 函数,导致多个函数中彼此调用并逐层使用 await,从而使每个函数都变成了 async 函数。这导致整个调用链条都变成了异步操作,增加了代码复杂度,这也就是异步的传染性。

async function getUser() {// 异步加载return await fetch('https://jsonplaceholder.typicode.com/users');
}async function m1() {const user = await getUser();// other wordsreturn user;
}async function m2() {const user = await m1();// other wordsreturn user;
}async function m3() {const user = await m2();// other wordsreturn user;
}async function main() {const user = await m3();// other wordsreturn user;
}

这段代码本身没有什么影响,但是在函数式编程中,会有很大的影响。

要求:将所有的 async 全部去掉但不影响代码的运行。

2. 解决方法

这个现象的根源在于 fetch 函数是异步的,进而导致调用者都是 async 函数。那能不能将 fetch 函数修改呢?不可以,因为网络通信需要一定的时间。

如何处理呢?

核心思想是:抛出一个未决的 Promise,并利用调用方来监听这个 Promise 的完成状态,而不是在每个函数里直接处理 async 和 await,实现 "暂停等待" 的效果。

简要代码如下:

// 模拟一个简单的 fetch 函数
function mockFetch(url) {return new Promise((resolve, reject) => {console.log('Fetching data from:', url);setTimeout(() => {if (url === 'https://jsonplaceholder.typicode.com/users') {resolve({json: () => Promise.resolve([{ id: 1, name: 'John Doe' }]),});} else {reject('Invalid URL');}}, 1000);});
}function getUser() {// 异步获取数据,不使用 async/awaitreturn fetch('https://jsonplaceholder.typicode.com/users');
}function m1() {const user = getUser(); // 获取用户return user;
}function m2() {const user = m1(); // 调用 m1return user;
}function m3() {const user = m2(); // 调用 m2return user;
}function main() {const user = m3(); // 调用 m3return user;
}function execute(fn) {// 1. 替换 fetch 函数,模拟请求缓存机制const oldFetch = fetch; // 保存原始 fetchconst cache = {status: 'pending', // 状态:'pending', 'fulfilled', 'rejected'value: null, // 缓存的值};function newFetch(...args) {// 如果缓存状态是 fulfilled,直接返回缓存结果if (cache.status === 'fulfilled') {return Promise.resolve(cache.value);} // 如果缓存状态是 rejected,抛出缓存的错误if (cache.status === 'rejected') {throw cache.value;}// 如果没有缓存,发起请求并保存状态const promise = oldFetch(...args).then((res) => res.json()).then((data) => {cache.value = data;cache.status = 'fulfilled'; // 请求成功,缓存数据}).catch((error) => {cache.value = error;cache.status = 'rejected'; // 请求失败,缓存错误throw error;});// 抛出 promise 以暂停执行throw promise;}window.fetch = newFetch; // 替换 fetch 函数// 2. 尝试执行 fn 函数,如果捕获到 promise,等待其完成后重新执行try {fn(); // 尝试执行函数} catch (error) {if (error instanceof Promise) {// 捕获 promise,等待完成后重新执行error.then(() => {window.fetch = newFetch; // 保持 fetch 替换为新 fetchfn(); // 请求完成后重新执行window.fetch = oldFetch; // 恢复旧 fetch}).catch((err) => {console.error('Request failed:', err);});}}window.fetch = oldFetch; // 恢复 fetch
}// 替换为模拟 fetch 函数
window.fetch = mockFetch;// 执行代码
execute(main);

展示如下:main 函数成功执行两次。

代码上包含详细的解释,可以尝试一下这种方法。


http://www.mrgr.cn/news/57660.html

相关文章:

  • 执行 start.sh 脚本时打开一个单独的运行窗口
  • Debug-029-el-table实现自动滚动分批请求数据
  • ubuntu 用ss-TPROXY实现透明代理,基于TPROXY的透明TCP/UDP代理,在 Linux 2.6.28 后进入官方内核。
  • OpenText Fortify 静态代码分析器,静态应用程序安全性测试
  • 什么是微服务中的反应性扩展?
  • tomcat部署war包部署运行,IDEA一键运行启动tomacat服务,maven打包为war包并部署到tomecat
  • 【xilinx-versal】【Petalinux】Petalinux设置自启动程序或自启动脚本详解
  • Scrum 四个会议及正确召开方式
  • 华为ICT题库-云服务部分
  • SSD融合FERPlus模型实现面部情绪识别
  • C语言入门-选择结构
  • Navicat 安装
  • 每天5分钟玩转C#/.NET之C#实现多线程的4种方式
  • 1024-git忽略文件
  • 如何部署微信碰一下支付系统源码?详细教程!
  • 392. 判断子序列
  • Navict的入门使用
  • springboot069视频网站系统的设计与实现(论文+源码)_kaic
  • List、Set、数据结构、Collections
  • LeetCode 2730.找到最长的半重复子字符串
  • 怎么消除背景音乐保留人声?让人声清晰可辨
  • Stable Diffusion 3.5发布:图像生成新纪元,多模态AI的突破!
  • 深入浅出神经网络:从基础原理到高级应用
  • Redis 哨兵模式
  • 文字识别接口应用场景解析-身份证识别、发票识别API、车牌识别
  • 智能听诊器革新宠物健康监测