> 美容
解决异步的方法(解决异步)
导语:前端面试题-消除异步的传染性
什么是异步传染性?// 封装了一个ajax请求// 内部使用了await,所以函数也要标记为asyncasync function doRequest() { // fetech请求是异步,所以要用await await fetch(&39;).then((resp) => resp.json())}// m1调用了doRequest函数,doRequest是async函数,所以也得标记asyncasync function m1() { return await doRequest();}// m2调用了m1 函数,m1是async函数,所以也得标记asyncasync function m2() { return await m1();}// m3调用了m2函数,m2是async函数,所以也得标记asyncasync function m3() { return await m2();}
fetch这个节点是异步的造成了连锁反应一个节点发生了异步,这个节点的所有调用链路全部都得异步函数式编程的场景,m1、m2、m3就不是纯函数了,全部变成了副作用目标去掉所有的async await,改成同步调用直接返回结果(ps: 异步的怎么会马上、立刻、直接返回结果呢?)function doRequest() { return fetch(&39;);}function m1() { return doRequest();}function m2() { return m1();}function m3() { return m2();}function main() { const res = m3(); console.log(res);}
怎么消除异步?异步肯定不能马上、立刻、直接返回结果只有报错这一条路把promise作为异常抛出函数开始执行,调用fetch发送请求不用等待fetch请求的返回结果,直接把fetch请求返回的promoise实例作为异常抛出fetch请求是异步的,需要把真正请求的返回值缓存起来,供后面的逻辑使用对真正的要执行的函数用try-catch包裹,捕获刚刚抛出的异常如果捕获的异常对象是Promise的实例, 就监听其成功或失败状态,成功或者失败后重新发起请求重新发起请求,会从缓存中直接获取上次请求缓存下的结果function doRequest() { return fetch(&39;);}function m1() { return doRequest();}function m2() { return m1();}function m3() { return m2();}function main() { const res = m3(); console.log(res);}function run(func) { // 缓存 let cache = []; // 请求索引 let i = 0; // 原生fetch let _originFetch = window.fetch; // 劫持fetch函数-代理原生fetch // 新fetch的核心功能: 1. 发送请求 2.报错 window.fetch = (...args) => { if (cache[i]) { if (cache[i].status === &39;) { return cache[i].data; } else if (cache[i].status === &39;) { throw cache[i].err; } } const result = { status: &39;, data: null, err: null, } cache[i++] = result; // 发送异步请求 const promise = _originFetch(...args) .then(resp => resp.json()) .then(resp => { result.status = &39;; result.data = resp; }, err => { result.status = &39;; result.err = err; }); // 马上报错, 让函数强制执行完毕,不用等异步回来才往下执行 // 把原生fetch的promise作为错误直接抛出去,让fetch马上结束 throw promise; } // 劫持原生fetch函数报错后,就会try-catch住 try { // 运行传入的函数 func(); } catch (err) { if (err instanceof Promise) { const reRun = () => { // index 置零 i = 0; // 重新发起请求 func() } // 异步请求成功或者失败都重新执行原来的函数 err.then(reRun, reRun); } } }run(main);
React中的应用const userResource = get UserResource();function ProfilePage () { return ( <Suspense fallback={<h1>Loading...</h1>}> <ProfileDetails /> </Suspense> )}function ProfileDetails () { console.log(1) // 直接throw一个Promise则一直处于loading状态 // throw new Promise(); const user = userResource.read(); return <h1>{user.name}</h1>}
Suspense里面子组件ProfileDetails的状态,请求中就显示loading,返回结果后就显示用户详情React中ProfileDetails组件没有返回Promise,就是一个普通的组件1会打印两次和上面的原理一样,先执行ProfileDetails,会打印第一次,直接throw一个promoise的异常成功后继续再执行一次,然后打印第二次
本文内容由小楠整理编辑!