当前位置: 首页 > 知识库问答 >
问题:

javascript - websocket会实时发送大量数据,导致页面卡顿?

黄啸
2023-09-07

websocket会实时发送大量数据时,我目前写的这些代码,会导致页面卡顿,性能优化我不知道怎么下手了,求大佬指教一下, 有偿。谢谢大佬们

let socketInfo = 'xxxx'let ws = new WebSocket(socketInfo)let pingInterval = ref(null) // 心跳间隔IDlet viewer = nulllet entity = nulllet polylineInitialized = false; // 轨迹线是否已初始化的标志let polylineEntity = null; // 用于存储轨迹线实体let pointEntity = null;const bufferLimit = 50; // 缓冲区大小限制,可以根据需求调整// 从服务器获取用户角色名const userRole = computed(() => {  return window.localStorage.getItem('roles')})const dropdown1 = ref()// 点击地图获取经纬度let longitude = ref(null);let latitude = ref(null);onMounted(() => {  init() //加载3d地图,  bindUid()//判断是否绑定uid  LocusModel()//3D地图模型})// 地图的基础配置function init() {  viewer = new Cesium.Viewer('cesiumContainer', {    //cesium的查看器的基本属性    baseLayerPicker: false,//配置图层底图的图标    //加载谷歌影像地图,UrlTemplateImageryProvider该接口是加载谷歌地图服务的接口    imageryProvider: new Cesium.ArcGisMapServerImageryProvider({      // url: "https://map.geoq.cn/arcgis/rest/services/ChinaOnlineStreetPurplishBlue/MapServer",      url: 'https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer' //卫星地图    })}// 判断是否绑定uidfunction bindUid(params) {  if (window.localStorage.getItem('CardUID') === '') {    return ElMessage({      message: '车辆终端ID未绑定,请点击右上角的“设置”图标进行绑定。',      type: 'warning',      showClose: true    });  } else {    webValue()  }}// 加载websocketfunction webValue() {  let oldPositionParams = [];//初始化一个变量来存储旧数据  let positionParams = []; // 用于存储所有的位置参数数据  // 初始Websocket  const onOpen = () => {    const data = JSON.stringify({ command: 1, serializeAlgorithm: 1, token: window.localStorage.getItem('token') });    ws.send(data); // 发送JSON字符串    // 设置心跳间隔为5秒    pingInterval.value = window.setInterval(() => {      const pingMessage = JSON.stringify({        command: 2,        serializeAlgorithm: 1      });      ws.send(pingMessage);    }, 5000);  };  // 接收websocket数据  const onMessage = async (event) => {    const data = JSON.parse(event.data);    if (data.data == undefined) {      console.log('未响应');    } else {      processPositionParams(data.data);      updateCarModelPosition(positionParams);// 实时更新车辆移动位置      if (!polylineInitialized) {        initializePolyline(positionParams); // 初始化轨迹线        polylineInitialized = true;// 标记轨迹线已初始化      } else {        updatePolylinePosition(positionParams); // 更新轨迹线位置      }      updateEntityPositions(positionParams); // 更新实体点的位置和标签文本。    }  };  function processPositionParams(data) {    const targetingTypes = {      0x10: 'RTK',      0x11: 'UWB',      0x12: '融合'    };    const newPositionParam = {      TargetingType: targetingTypes[data.type],      UID: data.uid,      Angle: data.angle,      Height: data.height,      longitude: data.longitude,      latitude: data.latitude    };    if (oldPositionParams.length > 0) {      const oldPosition = oldPositionParams[oldPositionParams.length - 1];      if (isNewDataDifferent(newPositionParam, oldPosition)) {        positionParams.push(newPositionParam);        if (positionParams.length > bufferLimit) {          positionParams.shift();        }      }    } else {      positionParams.push(newPositionParam);    }    oldPositionParams.push(newPositionParam);    if (oldPositionParams.length > bufferLimit) {      oldPositionParams.shift();    }  }  function isNewDataDifferent(newData, oldData) {    // 比较各个参数是否不同,如果有任何一个参数不同,就返回 true 表示数据不同    if (      newData.TargetingType !== oldData.TargetingType ||      newData.UID !== oldData.UID ||      newData.Angle !== oldData.Angle ||      newData.Height !== oldData.Height ||      newData.longitude !== oldData.longitude ||      newData.latitude !== oldData.latitude    ) {      return true; // 数据不同    }    return false; // 数据相同  }  const onClose = () => {    window.clearInterval(pingInterval.value); // 清除心跳间隔定时器    console.log('Websocket连接关闭');    webValue();  };  const onError = (error) => {    console.log('Websocket连接错误');    ws.close();    window.clearInterval(pingInterval.value); // 清除心跳间隔定时器    webValue();  };  ws.addEventListener('open', onOpen);  ws.addEventListener('message', onMessage);  ws.addEventListener('close', onClose);  ws.addEventListener('error', onError);}// 点击按钮是否显示轨迹点和轨迹线let checkedPoint = ref(true);let checkedLines = ref(false);// 保存checkedPoint和checkedLines的值到LocalStoragefunction saveCheckedValues() {  localStorage.setItem('checkedPoint', JSON.stringify(checkedPoint.value));  localStorage.setItem('checkedLines', JSON.stringify(checkedLines.value));}// 从LocalStorage中获取checkedPoint和checkedLines的值function loadCheckedValues() {  const storedCheckedPoint = localStorage.getItem('checkedPoint');  const storedCheckedLines = localStorage.getItem('checkedLines');  if (storedCheckedPoint) {    checkedPoint.value = JSON.parse(storedCheckedPoint);  }  if (storedCheckedLines) {    checkedLines.value = JSON.parse(storedCheckedLines);  }}// 监听checkedPoint和checkedLines的变化,并保存到LocalStoragewatch([checkedPoint, checkedLines], saveCheckedValues, { deep: true });// 在页面加载时加载checkedPoint和checkedLines的值window.addEventListener('load', loadCheckedValues);// 车辆模型let carModelData = null;let shouldFollowCar = false; // 标志位function updateCarModelPosition(positions) {  if (positions.length === 0) {    return;  }  const latestPosition = positions[positions.length - 1];  const cartesian3 = Cesium.Cartesian3.fromDegrees(latestPosition.longitude, latestPosition.latitude, 0.4);  if (!carModelData) {    createCarModel(cartesian3, latestPosition.Angle);  } else {    carModelData.position = cartesian3;    const headingPitchRoll = new Cesium.HeadingPitchRoll(      Cesium.Math.toRadians(latestPosition.Angle + 90),      Cesium.Math.toRadians(0),      Cesium.Math.toRadians(0)    );    carModelData.orientation = Cesium.Transforms.headingPitchRollQuaternion(cartesian3, headingPitchRoll);  }}function createCarModel(cartesian3, angle) {  const headingPitchRoll = new Cesium.HeadingPitchRoll(    Cesium.Math.toRadians(angle + 90),    Cesium.Math.toRadians(0),    Cesium.Math.toRadians(0)  );  const scaleByDistance = new Cesium.NearFarScalar(200, 120, 1200, 0.6);  const distanceDisplayCondition = new Cesium.DistanceDisplayCondition(0, 10000);  carModelData = viewer.entities.add({    position: cartesian3,    orientation: Cesium.Transforms.headingPitchRollQuaternion(cartesian3, headingPitchRoll),    model: {      uri: "http://127.0.0.1:5501/car/scene.gltf",      scale: 75,      scaleByDistance,      distanceDisplayCondition,    },    id: 'carModel' // 添加id属性  });}// 轨迹点 and 标签文字let positionsArray = [];let entityList = [];function updateEntityPositions(positions) {  for (let i = 0; i < positions.length; i++) {    let entityIndex = entityList.length;    const position = positions[i];    // 创建每个实体点的文本标签    const labelText = `终端ID:${position.UID},定位类型:${position.TargetingType}\n经度:${position.longitude},纬度:${position.latitude}\n角度:${position.Angle},高度:${position.Height}`;    if (i < entityList.length) {      // 如果实体点已经存在,只需更新位置和文本      const cartesian3 = Cesium.Cartesian3.fromDegrees(        position.longitude,        position.latitude,        0.02      );      entityList[i].position = cartesian3;      // 更新标签文本      entityList[i].label.text = labelText;    } else {      // 如果实体点不存在,创建一个新的实体点      const cartesian3 = Cesium.Cartesian3.fromDegrees(        position.longitude,        position.latitude,        0.02      );      const pointLabel = new Cesium.Entity({        position: cartesian3,        point: {          pixelSize: 10,          color: Cesium.Color.BLUE,          show: checkedPoint.value,          outlineColor: Cesium.Color.WHITE,          distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 500),          scaleByDistance: new Cesium.NearFarScalar(100, 1, 300, 0.5),          outlineWidth: 1,        },        label: {          text: labelText, // 设置不同的文本          font: '14pt monospace',          show: new Cesium.CallbackProperty(() => {            return entityIndex === entityList.length - 1;          }, false),          style: Cesium.LabelStyle.FILL_AND_OUTLINE,          outlineWidth: 2,          verticalOrigin: Cesium.VerticalOrigin.BOTTOM,          pixelOffset: new Cesium.Cartesian2(0, -9),          scaleByDistance: new Cesium.NearFarScalar(300, 1, 1200, 0.4),          scale: 1,          fillColor: Cesium.Color.WHITE,          outlineColor: Cesium.Color.WHITE,        },      });      entityList.push(pointLabel);      viewer.entities.add(pointLabel);    }  }  // 移除多余的实体点(如果有的话)  if (entityList.length > positions.length) {    for (let i = positions.length; i < entityList.length; i++) {      viewer.entities.remove(entityList[i]);    }    entityList.length = positions.length; // 调整数组的长度  }}// 创建新的轨迹线let polylineGeometry = null;let geometryInstance = null;function initializePolyline(positions) {  const positionsArray = positions.flatMap(pos => [pos.longitude, pos.latitude]);  const positionsInCartesian = Cesium.Cartesian3.fromDegreesArray(positionsArray);  polylineGeometry = new Cesium.PolylineGeometry({    positions: positionsInCartesian,    width: 5,    distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 500),    scaleByDistance: new Cesium.NearFarScalar(100, 10, 500, 1),  });  geometryInstance = new Cesium.GeometryInstance({    geometry: polylineGeometry,    attributes: {      color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.RED)    }  });  const primitive = new Cesium.Primitive({    geometryInstances: geometryInstance,    appearance: new Cesium.PolylineMaterialAppearance({      material: Cesium.Material.fromType(Cesium.Material.ColorType)    })  });  viewer.scene.primitives.add(primitive);}// 更新轨迹线位置function updatePolylinePosition(positions) {  if (geometryInstance) {    const positionsArray = positions.flatMap(pos => [pos.longitude, pos.latitude]);    const positionsInCartesian = Cesium.Cartesian3.fromDegreesArray(positionsArray);    polylineGeometry.positions = positionsInCartesian;    geometryInstance.geometry = polylineGeometry;    geometryInstance.show = checkedLines.value;  }}// 获取父组件传递的停车场信息的经纬度let props = defineProps({  cesiumData: Object,})// 3D地图模型function LocusModel() {  let modelMatrix = new Cesium.Transforms.eastNorthUpToFixedFrame(new Cesium.Cartesian3.fromDegrees(104.2255077, 30.57514052)); // gltf数据加载位置(自定义)  let heading = Cesium.Math.toRadians(66); // 设置旋转角度  let orientation = Cesium.Matrix4.fromRotationTranslation(    Cesium.Matrix3.fromRotationZ(heading),    Cesium.Cartesian3.ZERO  );  modelMatrix = Cesium.Matrix4.multiply(modelMatrix, orientation, new Cesium.Matrix4());  viewer.scene.primitives.add(    new Cesium.Model.fromGltf({      url: 'http://127.0.0.1:5501/parking/lq_parking_space.gltf', //gltf文件的URL      modelMatrix: modelMatrix,      scale: 1,      maximumSize: 1,      minimumPixelSize: 0.1,      scaleByDistance: new Cesium.NearFarScalar(300, 1, 1200, 0.5), //设置随图缩放距离和比例      distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 10000), //设置可见距离 10000米可见    }));}

共有1个答案

颜森
2023-09-07

下面的修改:1.用Map来存储位置参数,可以更快查到和更新数据。2.在onMessage事件里,用setTimeout来设置下一次心跳,而不用setInterval这个处理。加了一个重连机制,在onClose和onError事件里,如果WebSocket连接关闭或发生错误,会在5秒后重连。用requestAnimationFrame来更新实体位置,这样可以较少页面卡的情况。

整体的结构可以参考一下:

let positionParams = new Map(); // 用Map来存储位置function webValue() {  let reconnectInterval = null;  const onOpen = () => {    // ... (其他代码)    clearTimeout(reconnectInterval);  };  const onMessage = async (event) => {    // ... (其他代码)    clearTimeout(pingInterval.value);    pingInterval.value = setTimeout(sendHeartbeat, 5000);  };  const onClose = () => {    console.log('Websocket连接关闭');    reconnectInterval = setTimeout(webValue, 5000);  };  const onError = (error) => {    console.log('Websocket连接错误', error);    reconnectInterval = setTimeout(webValue, 5000);  };  // ... (省略其他代码)}function processPositionParams(data) {  // ... (其他代码)  const newPositionParam = {    // ... (其他代码)  };  const oldData = positionParams.get(data.uid);  if (!oldData || isNewDataDifferent(newPositionParam, oldData)) {    positionParams.set(data.uid, newPositionParam);  }}function isNewDataDifferent(newData, oldData) {  // ... (其他代码)}function updateEntityPositions() {  requestAnimationFrame(() => {    positionParams.forEach((position, uid) => {      // 更新实体位置    });  });}// ... (其他代码)
 类似资料:
  • echarts通过websocket频繁更新散点图数据,数据量大的时候达到三四千左右,页面出现卡顿现象,鼠标一直在转。无法准确选中数据tooltip,页面卡死。 版本更新到最新版,页面销毁清除均无效

  • 我遇到的问题是,当尝试从Spring Websocket服务器(托管在Tomcat上)发送数据时,似乎在尝试发送消息的过程中重置了连接。当发送大量二进制数据(在这里的示例中为5526584字节)时,该错误似乎发生得更多,但我也看到它发生在文本通道上,并且数据较少。然而,发送超过5左右MB似乎会使其相对稳定地崩溃。 EDIT-下面的end Edit块是服务器端代码和错误。我现在相信错误是在服务器端引

  • 问题内容: 我正在使用Grails 1.1 beta2。我需要将大量数据导入Grails应用程序。如果我反复实例化grails域类然后保存它,则性能会降低到无法接受的程度。以从电话簿导入人为例: 事实证明这是缓慢的。Grails邮件列表上的某人建议在事务中分批保存。所以现在我有: 这必须至少在开始时更快。每笔交易会保存500条记录。随着时间的流逝,交易花费的时间越来越长。最初的几笔交易大约需要5秒

  • 问题内容: 快速的问题,我已经尝试自己弄清楚这一点,但是在试图弄清页面为什么或如何重新加载以及正在/不应该执行其应做的工作时,使用会话变量可能会造成混淆。 在任何(非脚本)情况下,页面重新加载(使用JavaScript,f5,ctrl + f5,浏览器重新加载按钮等)是否会导致表单重新发布? (这与在C#代码中使用IfPost分支有关,例如下面的示例代码): 我只是需要知道在这里期望什么,以便可以

  • 7.15一面: 1.自我介绍 2.项目深挖(聊了很久) 3.对数仓的看法 4.主题域及其建设过程(要落地,谈业务过程) 5.讲一个熟悉的指标体系构建(没做过) 6.为什么不考研 7.为什么想跳槽 8.sql留存率(讲了下思路就行了) 反问: 1.为啥晚上6点还面试,唯品会不是955吗 2.唯品会的计算引擎选型是什么 ------------------------- 挂了

  • 场景: 我只有一个生产者和消费者,只有一个队列来传输消息。使用者将根据已使用该值的消息更新DB上的值。不应将任何操作并行发送到DB。所以,我们不应该做任何导致数据库上数据并发的事情。我使用一次接收一条消息。删除是否会导致多个操作并行发送到DB?