导出异步等待变量并在 JS 中完成“等待”后将其导入另一个文件
Posted
技术标签:
【中文标题】导出异步等待变量并在 JS 中完成“等待”后将其导入另一个文件【英文标题】:Export an async await variable and import it to another file once its done "awaiting" in JS 【发布时间】:2021-05-14 18:25:19 【问题描述】:我刚开始用 JS 编码为我的脚本创建一个网站,但我遇到了一些菜鸟问题。
我正在通过连接到 fetch 函数的异步等待函数更新变量。我想在另一个脚本中渲染我的变量,这样做会让人头疼。
这是我目前所拥有的,但似乎第二个文件正在导入 nul 变量。
这是我的计算和变量声明文件:
var url = 'https://financialmodelingprep.com/api/v3/profile/'+tickersymb+'?apikey='+api
var priceStat = "Working..."
var jsonData
function checkStats(url, callback)
return fetch(url)
.then((response) =>
return response.json().then((data) =>
console.log(data);
return data;
).catch((err) =>
console.log(err);
)
);
(async () =>
jsonData = await checkStats(url)
priceStat = jsonData.[0].price
exports.jsonData = jsonData
exports.priceStat = priceStat
exports.tickersymb = tickersymb
)();
这是我的渲染脚本:
var compute = require('components/compute-engine');
var pricestat = compute.pricestat;
var tickersymb = compute.tickersymb;
var jsonData = compute.jsonData;
export default function HeaderStats()
return (
<>
/* Header */
<div className="relative bg-blue-600 md:pt-32 pb-32 pt-12">
<div className="px-4 md:px-10 mx-auto w-full">
<div>
/* Card stats */
<div className="flex flex-wrap">
<div className="w-full lg:w-6/12 xl:w-3/12 px-4">
<CardStats
statSubtitle=""
ticker= tickersymb
exchange="NASDAQ"
statIconName="fas fa-dollar-sign"
statIconColor="bg-green-500"
/>
...
【问题讨论】:
您无法将异步代码转换为同步代码。这些出口也必须是承诺,进口商必须等待它们。 感谢您的回复!我如何让进口商等待? 要么导出promise本身,要么导出一个返回promise的函数。然后使用await
或 .then()
等待承诺(或返回的承诺)
【参考方案1】:
没有办法像这样将异步代码转换为同步代码,无论是跨模块还是在文件内。一旦进入异步链,您将永远无法将控制权重新交给同步代码,因为所有同步调用堆栈帧都需要在异步函数有机会解决之前完成。
因此,您需要导出一个 promise,然后在导入器代码中 await
它。
您可以应用一些模式,如果没有看到更大的设计上下文,我不确定哪种模式最好,但我不会尝试对这些单独的变量中的每一个使用承诺——它不会使感觉你是否想一起使用它们(Promise.all
可以做到这一点,但它不是一个对客户端友好的界面)。
相反,我建议导出一个函数,或者直接导出checkStats
,或者使用一个包装器进行索引,以便为消费者整齐地准备数据,返回打包到一个对象中的数据。
看来您的意图是只获取一次数据。如果您担心该函数会在每次重新渲染时继续访问 API,那么一旦一个承诺得到解决,进一步调用 await
该承诺只会返回旧值而不是重新计算它。在下面的示例代码中,我只使用了一个 Promise 并将其存储在一个变量中,因此无论 getStats
被调用多少次,fetch
都只会被调用一次。
您的导入器应在等待承诺解决时提供默认值(您通常可以将它们导出为单独的同步变量,但为什么数据获取模块要关心 UI/视图问题?我会将其保留在导入器中)。
最后,看起来您正在使用 React,因此组件需要以某种效果使用这些数据,而不是在组件外部的同步代码中。如果您只想获取一次数据,请使用[]
作为useEffect
的第二个参数或将数据缓存在闭包中。
这里有一个玩具例子来说明:
<script type="text/babel" defer>
/**** mocks ****/
const fetch = async () =>
console.log("fetch call made");
return
json: () => new Promise(resolve =>
setTimeout(() => resolve([price: 42]), 1000)
)
;
;
const exports = ;
const require = () => exports;
/**** exporter file ****/
const url = "https://www.example.com";
const checkStats = url =>
fetch(url)
.then(response => response.json())
.catch(err => console.error(err))
;
// cache the promise
const stats = checkStats(url)
.then(jsonData => (price: jsonData[0].price))
;
exports.getStats = () => stats;
/**** importer file ****/
const useState, useEffect = React;
const getStats = require("./your-other-module");
const HeaderStats = () =>
const [price, setPrice] = useState("loading...");
useEffect(() =>
getStats().then(data => setPrice(data.price));
, [price]);
return (<h1>price</h1>);
;
// show that even with 2 renders, fetch is
// only called once (open browser console)
ReactDOM.render(
[<HeaderStats />, <HeaderStats />],
document.body
);
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.26.0/babel.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
【讨论】:
以上是关于导出异步等待变量并在 JS 中完成“等待”后将其导入另一个文件的主要内容,如果未能解决你的问题,请参考以下文章