什么叫异步传染性?
async/await 是 Generator 函数的语法糖,是对 Promise 的封装。但它是具有传染性的:
如果一个底层函数使用了 async,那么所有基于它的所有调用链都必须使用 await 获取结果,或者使用 .then()。当处于函数式编程里面,纯函数,全部都变成异步函数了。
async function getData() { return fetch('http://localhost:4200/XXXX').then((res) => res.json()); } async function funA() { // other code return await getData(); } async function funB() { // other code return await funA(); } async function main() { const data = await funB(); console.log(data) }
如何消除异步传染性?
首先,我们要想办法把异步函数变成同步函数
function getData() { return fetch('http://localhost:4200/XXXX').then((res) => res.json()); } function funA() { // other code return getData(); } function funB() { // other code return funA(); } function main() { const data = funB(); console.log(data) }
最后返回一个Promise
找到异步发生的根本
fetch所以需要想办法解决
fetch,让fetch函数立即返回结果?但是这里获取远程数据需要时间来处理,第一时间返回的数据肯定不能用,会导致报错。大概流程:
graph LR; id(函数开始) --首次执行--> fetch; fetch --不用等待结果强制报错--> 引发错误; 引发错误 --> 函数结束; fetch --2远程获取数据--> data; data --2--> 缓存data; 缓存data --2再次执行函数--> 函数开始; 函数开始--3--> fetch; fetch --3存在缓存--> 交付data; 交付data --3--> 函数继续; 函数继续 --3--> 函数结束;
function getData() { return fetch('http://localhost:4200/XXXX'); } function run(func) { // 第一步,想办法重写fetch函数 // 发送请求,然后报错, // 如果有缓存则交付缓存结果 let cache = []; // 缓存多次函数结果 let i = 0; //运用下标,反正第i次运行结果 const _originalFetch = window.fetch; window.fetch = (...args) => { if(cache[i]) { // 如果缓存存在 // 检查缓存(promise)状态 if(cache[i].status === 'fulfilled') { // 交付缓存结果 return cache[i].data; } else if(cache[i].status === 'rejected') { throw cache[i].error; } } // 定义结果 const result = { status: 'pending', // 状态 data: null, error: null } cache[i++] = result; // 发送请求 const prom = _originalFetch(...args).then((resp) => resp.json()).then( resp => { result.status = 'fulfilled'; result.data = resp; }, error => { result.status = 'rejected'; result.error = error ; } ) // 报错, 把prom作为错误抛出 throw prom } try { func(); } catch(error) { // 获取报错,引发重新执行函数 if(error instanceof Promise) { const reRun = () => { i = 0; func(); } error.then(reRun,reRun) } } } function main() { const data = getData(); console.log(data) } run(main)