d3.js、JavaScript中如何从Promise返回非pending状态的已决议值?
问题根本原因
所有被async关键字修饰的函数,JavaScript语言规范会强制将它的返回值包装为Promise对象,这是固定规则,和你函数内部返回什么值无关。你在函数内部await拿到的是解析后的值,但是返回的时候会被自动再包一层Promise,所以你直接调用async函数拿到的永远是Promise实例,不可能直接拿到原始值。
可行解决方案
以下方案均可以避免重复编写异步代码,符合你的使用需求:
方案1:全局变量缓存+初始化预加载
适合所有用到数据的逻辑都可以在数据加载完成后再执行的场景,后续使用完全不需要写异步代码:
// 提前定义全局缓存变量 let countryData = null; async function init() { // 页面初始化阶段就加载数据,赋值给全局变量 countryData = await generateCountryData(); // 所有依赖该数据的业务逻辑,都在拿到数据后再调用 runBusinessLogic(); } // 后续任何普通同步函数里都可以直接使用 function runBusinessLogic() { // 直接读取全局变量,拿到的就是解析完成的数组 console.log(countryData); } // 页面加载时启动初始化 window.onload = init;
方案2:缓存Promise实例,避免重复异步逻辑
如果没法保证业务逻辑的执行顺序,或者部分逻辑可能在数据加载完成前触发,可以直接缓存Promise实例,每次使用时await即可,只会发起一次请求,也不需要重复定义异步逻辑:
// 只调用一次生成数据的函数,缓存Promise实例 const cachedCountryDataPromise = generateCountryData(); // 任何需要用到数据的地方,直接await这个缓存的Promise即可 async function needDataFunction1() { const data = await cachedCountryDataPromise; // 处理逻辑 } async function needDataFunction2() { const data = await cachedCountryDataPromise; // 不会重复请求csv,直接拿已解析的结果 // 处理逻辑 }
注:await已经处于fulfilled状态的Promise没有额外开销,会直接返回解析后的值,不需要担心性能问题。
方案3:入口处一次性获取数据,传参给下游同步函数
只在最上层的入口函数里用一次async/await,拿到数据后作为参数传给所有下游的同步业务函数,下游函数完全不需要写异步逻辑:
// 所有业务函数都是普通同步函数,不需要async修饰 function processData(data) { // 数据处理逻辑 } function renderD3Chart(data) { // d3渲染逻辑 } // 仅在最上层入口处使用一次异步逻辑 async function mainEntry() { const countryData = await generateCountryData(); // 把数据作为参数传给所有需要的同步函数 processData(countryData); renderD3Chart(countryData); } mainEntry();
注意JavaScript的异步IO规则无法突破,不存在任何方法可以同步获取到异步请求(比如d3.csv的网络请求)的结果,上述方案都是在现有规则下减少重复异步代码的最优实践。
内容的提问来源于stack exchange,提问作者ThincThru
相关产品推荐
相关产品推荐

