导出一个异步等待变量,并在 JS 中"awaiting"完成后将其导入另一个文件



我刚开始用JS编码,为我的脚本制作一个网站,但我有一些新手问题。

我通过连接到fetch函数的async await函数更新变量。我想在另一个脚本中呈现我的变量,这样做已经导致安静的头痛。

这是目前为止我所做的,但似乎第二个文件正在导入null变量。

这是我的计算和变量声明文件:
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"
/>
...

没有办法像这样将异步代码转换为同步代码,无论是跨模块还是在文件内。一旦你进入异步链,你就永远不能把控制权交还给同步代码,因为所有同步调用堆栈帧都需要在异步函数有机会解析之前完成。

因此,您需要导出一个承诺,然后在导入器代码中对其进行await

有一些模式你可以应用,我不确定哪一个是最好的没有看到一个更大的设计上下文,但我不会试图使用每个这些单独的变量的承诺-这是没有意义的,如果你想使用他们所有在一起(Promise.all可以做到,但它不是一个客户端友好的界面)。

相反,我建议导出一个函数,要么是直接的checkStats,要么是一个包装器,它做索引,为消费者整齐地准备数据,返回打包成对象的数据。

看来你的意图是只获取一次数据。如果你担心这个函数会在每次渲染时都碰到API,一旦promise被解决了,对await的进一步调用只会返回旧的值,而不是重新计算它。在下面的示例代码中,我只使用一个promise并将其存储在一个变量中,因此无论getStats被调用多少次,fetch都只被调用一次。

你的导入器应该在等待promise解析的时候提供默认值(通常你可以将它们导出为单独的同步变量,但是为什么数据获取模块要关心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>

最新更新