wordpress站点很慢,网站模板flash,开发网站怎么挣钱,怎样申请电子邮箱文章目录 概述观点无法解决可以解决 来源 概述
异步传染性问题通常是指#xff0c;当一个函数使用了async和await#xff0c;其调用者也需要使用async和await处理异步操作#xff0c;导致整个调用链都变成异步的。这种情况可能导致代码变得更复杂#xff0c;不… 文章目录 概述观点无法解决可以解决 来源 概述
异步传染性问题通常是指当一个函数使用了async和await其调用者也需要使用async和await处理异步操作导致整个调用链都变成异步的。这种情况可能导致代码变得更复杂不易维护。
类似于C# try catch的层层上抛在某一层catch
观点
查了很多资料 对于这个问题说法还都不一样
async/await异步传染性无法解决可以解决但开销不小/ 解决代价不大
无法解决 在node 的層面沒法解決 除非v8 或者jscore等等提供 GMP 模型Socket 勾子。 不是该考虑怎么消除async而是该考虑怎么在需要的时候给任意程序入口加一个异步上下文。除此之外任何想要在程序中段消除async的需求都是伪需求。 可以解决
合理分层将异步操作集中在特定层次例如数据访问层或API调用层这样可以将异步操作限制在这些层次而不会传播到整个代码库。在这种架构下其他层次的代码可以保持同步方式处理数据从而降低代码复杂度。使用Promise当使用async和await时实际上底层是基于Promise的。你可以尽量使用Promise链式调用.then()和.catch()在某种程度上减少异步传染性。但请注意过度使用Promise链式调用可能导致回调地狱问题。使用事件驱动异步传染性问题有时候是因为代码逻辑紧密耦合所导致的。考虑使用事件驱动架构通过发布和订阅事件的方式来解耦代码。这样即使某个操作是异步的它也不会影响到其他操作的同步性。限制异步操作的范围尽量让异步操作独立不要过多地依赖其他异步操作的结果。如果确实需要依赖其他异步操作的结果尝试将这些操作分组并使用Promise.all()或Promise.race()等方法来处理。避免不必要的异步操作不要将原本可以用同步方式实现的操作变成异步操作。异步操作应该只用于真正需要的场景例如网络请求、文件读写等。ES2021 可以用top-level await封装异步操作将需要异步操作的函数封装成一个单独的函数该函数内部使用 async/await 来处理异步逻辑。然后在需要调用这个异步函数的地方可以直接调用它而不需要在调用者处添加 async/await。使用异步函数的返回值如果调用异步函数的结果在调用者中不需要立即使用可以简单地返回异步函数的 Promise 对象而不是在调用者处添加async/await。然后在需要使用结果的地方再使用 async/await 处理。使用回调函数如果不适合使用async/await可以考虑使用回调函数的方式处理异步操作。将异步函数的回调函数传递给异步函数在回调函数中处理结果。
以下是一个简单的示例展示了如何将异步操作限制在数据访问层并使用事件驱动来解耦代码
数据访问层使用异步操作:
// dataAccessLayer.js
import axios from axios;export const fetchData async (url) {try {const response await axios.get(url);return response.data;} catch (error) {throw new Error(Error fetching data: ${error.message});}
};事件处理器处理数据访问层的结果发布事件:
// eventHandler.js
import EventEmitter from events;
import { fetchData } from ./dataAccessLayer;export const eventEmitter new EventEmitter();export const fetchAndEmitData async (url) {try {const data await fetchData(url);eventEmitter.emit(dataFetched, data);} catch (error) {eventEmitter.emit(dataFetchError, error);}
};主逻辑订阅事件处理事件结果:
// main.js
import { fetchAndEmitData, eventEmitter } from ./eventHandler;const onDataFetched (data) {console.log(Data fetched successfully:, data);
};const onDataFetchError (error) {console.error(Data fetch error:, error.message);
};// 订阅事件
eventEmitter.on(dataFetched, onDataFetched);
eventEmitter.on(dataFetchError, onDataFetchError);// 触发数据请求
fetchAndEmitData(https://api.example.com/data);在这个示例中我们将异步操作限制在了dataAccessLayer.js中。eventHandler.js负责处理这些异步操作的结果并发布相应的事件。main.js则订阅这些事件并处理它们的结果。这样我们在主逻辑中避免了使用async和await从而降低了代码复杂度。
还有一种解决方案很有意思是利用异常捕获达成的对其可行性表示怀疑
async function getUser() {return await fetch(./1.json);
}async function m1() {const user await getUser();return user;
}async function m2() {const user await m1();return user;
}
async function m3() {const user await m2();return user;
}async function main() {const user await m3();console.log(user);
}从上面的函数调用可以看出来getUser是异步函数所有使用和相关联的函数都必须使用async/await变成异步函数这样使用也没有什么问题但是在函数式编程环境中就不合适了。 本来这些函数应该是一个纯函数的却因为异步具有传染性导致这些函数全部变成副作用的了这在函数式编程环境中是很难接受的。
所以如何不去改动这些函数把这些异步全部去掉呢变成没有异步的样子从而保持这些函数的纯度。如下 function getUser() {return fetch(./1.json);
}function m1() {const user getUser();return user;
}function m2() {const user m1();return user;
}function m3() {const user m2();return user;
}function main() {const user m3();console.log(user);
}怎么操作呢getUser调用了fetch请求导致了异步的产生。 网络传输是需要时间的这个是无法改变的。让浏览器完全阻塞那就卡死了肯定是行不通的。 目前的函数调用流程如下 main-getUser-fetch - - 等待网络请求请求完成 -- getUser-main
由于fetch需要等待导致所有相关的函数都要等待。那么只能在fetch这里做一些操作了。如何让fetch不等待就只能报错了。 我们看下通过fetch报错如何解决这个问题。
main-getUser-fetch-error 拿到结果存入cache: main-getUser-fetch-cache-getUser-main
在调用fetch的时候不等待了而是报错这样所有函数都终止了调用栈层层弹出调用结束。
但是我们最终的目的是要拿到结果的前面虽然报错了网络线程仍然还在继续网络请求它不会停止直到拿到结果。
拿到结果后我们把它放在一个缓存中接着再去恢复整个调用链的执行。再执行fetch时结果已经缓存在cache了取出数据就可以直接交付不用等待了从而变成了同步函数。
整个过程会走两次第一次以错误结束第二次以成功结束这两次都是同步的。
在这个过程中fetch的逻辑就发生了变化 fetch时要判断是否有缓存如果有缓存则返回缓存如果没有缓存则发送真实请求同时抛出错误然后把请求的结果保存。抛出的错误为发送请求返回的Promise对象目的是为了在请求完成后再去恢复调用。
伪代码实现如下
function run(func) {let cache {status: pending,value: null};const oldFetch window.fetch;window.fetch function(...args){if(cache.status fulfilled){return cache.value;}else if(cache.status rejected){//之前的请求有问题throw cache.value;}else{// 1. 发送真是请求const promise oldFetch(...args).then(res{cache.status fulfilled;cache.value res;}, err {cache.status rejected;cache.value err;});// 2. 抛出错误throw promise;}}// 执行入口函数try {func();} catch (error) {if(error instanceof Promise) {// 不论成功还是失败都重新调用error.then(func,func).finally((){//恢复原来的值window.fetch oldFetch;});}}}
run(main);来源
在前端开发中如何消除异步的传染性 消除async/await异步的传染性 如何解决 async/await 的传染性