我使用this API建造了一个船用可视化仪。在查询API之后,我可以通过我感兴趣的容器获得json响应,并将这些API信息写入MongoDB
数据库中。
API请求可以每1分钟完成一次,因此我使用const NodeCache = require('node-cache');
模块绕过了1分钟的限制。
问题:一切似乎都运行良好,但是如果我手动刷新页面以查看船只的更新位置并在1分钟前发送请求,我会收到304
Unhandled promise rejection
中的。因此,该程序不会崩溃,但是会不断跳过1分钟,将信息写入MongoDB
。这意味着由于刷新页面操作而不是每1分钟一次,所以我每2分钟获得一次职位。为什么会这样?
UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
API的典型答案如下:
[
{
"AIS":{
"MMSI":227441980,
"TIMESTAMP":"2017-08-11 11:17:37 UTC",
"LATITUDE":46.1459,
"LONGITUDE":-1.16631,
"COURSE":360.0,
"SPEED":0.0,
"HEADING":511,
"NAVSTAT":1,
"IMO":0,
"NAME":"CLEMENTINE",
"CALLSIGN":"FJVK",
"TYPE":60,
"A":0,
"B":0,
"C":0,
"D":0,
"DRAUGHT":0.0,
"DESTINATION":"",
"ETA_AIS":"00-00 00:00",
"ETA":"",
"SRC":"TER",
"ZONE": "North Sea",
"ECA": true
}
}
]
在代码最重要的部分下面:
服务器
var express = require('express');
var router = express.Router();
var axios = require('axios');
const NodeCache = require('node-cache');
const myCache = new NodeCache();
let hitCount = 0;
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
router.get('/hello', async function(req, res, next) {
const allData = myCache.get('allData');
if (!allData) {
hitCount++;
try {
const { data } = await axios.get(
'https://api.vesselfinder.com/vesselslist?userkey=KEY'
);
const { metaData, ships } = data;
myCache.set('allData', data, 70);
console.log(data + 'This is the data');
res.send(data);
} catch (error) {
res.send(error);
console.log(error);
}
}
res.send(allData);
});
module.exports = router;
客户
class BoatMap extends Component {
constructor(props) {
super(props);
this.state = {
// .........
};
this.updateRequest = this.updateRequest.bind(this);
}
async componentDidMount() {
this.countDownInterval = setInterval(() => {
}, 500);
await this.updateRequest();
this.updateInterval = setInterval(() => {
this.updateRequest();
}, 60 * 1000);
}
async updateRequest() {
const url = 'http://localhost:3001/hello';
const fetchingData = await fetch(url);
const ships = await fetchingData.json();
console.log('fetched ships', ships);
if (JSON.stringify(ships) !== '{}') {
if (this.previousTimeStamp === null) {
this.previousTimeStamp = ships.reduce(function(obj, ship) {
obj[ship.AIS.NAME] = ship.AIS.TIMESTAMP;
return obj;
}, {});
}
this.setState({
ships: ships,
filteredShips: ships
});
this.props.callbackFromParent(ships);
for (let ship of ships) {
if (this.previousTimeStamp !== null) {
if (this.previousTimeStamp[ship.AIS.NAME] === ship.AIS.TIMESTAMP) {
this.previousTimeStamp[ship.AIS.NAME] = ship.AIS.TIMESTAMP;
console.log('Same timestamp: ', ship.AIS.NAME, ship.AIS.TIMESTAMP);
continue;
} else {
this.previousTimeStamp[ship.AIS.NAME] = ship.AIS.TIMESTAMP;
}
}
let _ship = {
// ships data ....
};
const requestOptions = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(_ship)
};
await fetch('http://localhost:3001/users/vessles/map/latlng', requestOptions);
}
}
}
}
render() {
const noHoverOnShip = this.state.hoverOnActiveShip === null;
// console.log("color", this.state.trajectoryColor);
return (
<div className="google-map">
<GoogleMapReact
// ships={this.state.ships}
bootstrapURLKeys={{ key: 'key' }}
center={{
lat: this.props.activeShip ? this.props.activeShip.latitude : 37.99,
lng: this.props.activeShip ? this.props.activeShip.longitude : -97.31
}}
zoom={5.5}
onGoogleApiLoaded={({ map, maps }) => {
this.map = map;
this.maps = maps;
// we need this setState to force the first mapcontrol render
this.setState({ mapControlShouldRender: true, mapLoaded: true });
}}
>
{this.state.mapLoaded ? (
<div>
<Polyline
map={this.map}
maps={this.maps}
markers={this.state.trajectoryData}
lineColor={this.state.trajectoryColor}
/>
</div>
) : (
''
)}
{/* Rendering all the markers here */}
{this.state.filteredShips.map((ship) => (
<Ship
ship={ship}
key={ship.AIS.MMSI}
lat={ship.AIS.LATITUDE}
lng={ship.AIS.LONGITUDE}
logoMap={this.state.logoMap}
logoClick={this.handleMarkerClick}
logoHoverOn={this.handleMarkerHoverOnShip}
logoHoverOff={this.handleMarkerHoverOffInfoWin}
/>
))}
我到目前为止所做的事情:
1)我也遇到this source来帮助我解决问题,但是没有运气。
2)我也咨询了this other source和this one,但是他们两个都没有帮助我找出问题所在。
3)我对问题进行了深入研究,发现了this source too。
4)我读了this one too。但是,这些都没有帮助我解决问题。
5)我还发现this source非常有用,但仍然没有解决办法。
非常感谢您指出解决此问题的正确方向。
答案 0 :(得分:1)
如错误所述,this.state.filteredShips.map
在某些情况下不是函数。这可能意味着您省略的初始状态没有this.state.filteredShips
作为Array
。如果您还没有过滤飞船,那没关系,但是渲染代码必须考虑道具和状态的所有可能性。如果您正在调用this.state.filteredShips.map
,而这不是函数,则渲染将失败。您应该检查this.state.filteredShips
的值并针对尚未填充的情况进行渲染,例如:
{Array.isArray(this.state.filteredShips)
? this.state.filteredShips.map((ship) => (
<Ship
ship={ship}
key={ship.AIS.MMSI}
lat={ship.AIS.LATITUDE}
lng={ship.AIS.LONGITUDE}
logoMap={this.state.logoMap}
logoClick={this.handleMarkerClick}
logoHoverOn={this.handleMarkerHoverOnShip}
logoHoverOff={this.handleMarkerHoverOffInfoWin}
/>
))
: 'Loading...'
}
答案 1 :(得分:0)
我了解您要设置状态cmd:
this.setState({
ships: ships,
filteredShips: ships
});
在进入
之前完成for (let ship of ships) {...
如果是这种情况,则需要使用setState回调:
this.setState({ ..... }, () => {do what you need next})
setState是异步的,除非您使用回叫,否则无法保证状态vars已发货,并且filteredShips将在进入循环之前获取所需的值。
另一方面,我从不使用await来呼叫服务器。如果我使用Axios,则倾向于使用其回调。有关更多信息,请访问:
https://www.npmjs.com/package/react-axios
希望这会有所帮助。