JS SSE:无法在 onMsg 回调函数之外访问 event.data?

JS SSE: Cannot access event.data outside of onMsg callback function?

我正在使用 three.js 在浏览器上以实时和 3D 形式可视化加速度计数据。我正在使用 server-sent-event 将数据从远程服务器传输到客户端。

我已经 three.js 代码和 运行 模拟数据并且没有呈现问题。现在当我尝试在远程服务器上使用SSE时,我发现我只能从onMsg、onOpen、onError回调函数中读取数据

出于这个原因,我在 onMsg 回调中放置了 three.js 实现,但在这种情况下,浏览器永远 运行 并且它基本上不显示渲染,它进入无限循环, 所以我认为我不应该在 Onmsg 中包含任何其他函数,因此,我将 three.js 代码与 SSE 分开,但现在我无法从 Onmsg 访问 event.data 并将它们发送回负责渲染 3D 模型的函数 main()。

下面是我的代码:

它只渲染 3D 模型(它是静态的),我可以在开发者工具 window 上看到 JSON 格式的数据,但数据没有传递到 3D 模型。

function main() {

    const canvas = document.querySelector('#canvas');
    const renderer = new THREE.WebGLRenderer({ canvas });
    var context = canvas.getContext("2d");

    const fov = 70;
    const aspect = 2;
    const near = 20;
    const far = 500;
    const color = 0xFFFFFF;
    const intensity = 1;
    const size = 10;
    const divisions = 10;
    const objects = [];
    const radius = 3;
    const widthSegments = 3;
    const heightSegments = 3;
    const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
    const sphereGeometry = new THREE.BoxGeometry(radius, widthSegments, heightSegments);
    const sunMaterial = new THREE.MeshBasicMaterial({ color: "green", wireframe: false });
    const sunMesh = new THREE.Mesh(sphereGeometry, sunMaterial)
    const light = new THREE.PointLight(color, intensity);
    // const gridHelper = new THREE.GridHelper(200000, 10000);

    camera.position.z = 0;
    camera.position.x = 100;
    camera.up.set(0, 0, 1);
    camera.lookAt(0, 0, 0);   

    const scene = new THREE.Scene();
    {
      const color = 0x00afaf;
      const intensity = 10;
      const light = new THREE.PointLight(color, intensity);
      scene.add(light);
      // gridHelper.geometry.rotateY(Math.PI / 2);
      // scene.add(gridHelper);
      // scene.add(light);
    }
    function resizeRendererToDisplaySize() {
    const canvas = renderer.domElement;
    const width = canvas.clientWidth;
    const height = canvas.clientHeight;
    const needResize = canvas.width !== width || canvas.height !== height;
    if (needResize) {
      renderer.setSize(width, height, false);
    }
    return needResize;
  }

  function resizeToClient() {
    const needResize = resizeRendererToDisplaySize()
    if (needResize) {
      const canvas = renderer.domElement;
      camera.aspect = canvas.clientWidth / canvas.clientHeight;
      camera.updateProjectionMatrix();
    }
  }

    var cubeAxis = new THREE.AxesHelper(10);
    sunMesh.add(cubeAxis);

    sunMesh.scale.set(5, 5, 5)
    scene.add(sunMesh);
    scene.background = new THREE.Color(0.22, 0.23, 0.22);

    function render() {

      sunMesh.position.x = 100;
      // sunMesh.rotation.y = -70.68;
    }
    resizeToClient();
    renderer.render(scene, camera);
    requestAnimationFrame(render);
  }


  function onMsg(event) {
    // console.log(`[message] Data received from server: ${event.data}`);
    // console.log("event.data = " + JSON.parse(event.data));

    var received_msg = event.data;

    var obj = JSON.parse(JSON.parse(received_msg));
    if (obj !== null) {
      if (
        obj.hasOwnProperty("DataMapChangedObjectsAddressValue") &&
        obj["DataMapChangedObjectsAddressValue"][0]["DataMapAddress"] !==
        undefined
      ) {
        let sensorAddr =
          obj["DataMapChangedObjectsAddressValue"][0]["DataMapAddress"];
        let sensorValue =
          obj["DataMapChangedObjectsAddressValue"][0]["Value"];

        //Accelerometer X Axis
        //if(sensorAddr === this.despToAddrMap.get("Accelerometer X Axis Data")){
        if (sensorAddr === 3) {
          console.log((sensorValue / 16384) * 500);
        }
      }
    }
  }

  function onOpen(e) {
    console.log("SSE connected");
  }

  function onError(e) {
    // console.log(`[error] ${error.message}`);
    if (e.eventPhase == EventSource.CLOSED) this.source.close();
    if (e.target.readyState == EventSource.CLOSED) {
      console.log("SSE Disconnected");
    } else if (e.target.readyState == EventSource.CONNECTING) {
      console.log("SSE Connecting ...");
    }
  }

  function StartRetrieveLiveData() {
    if (!!window.EventSource) {
      this.source = new EventSource("/sse");
    } else {
      console.log("Your browser doesn't support SSE");
    }

    this.source.addEventListener("message", e => this.onMsg(e));

    this.source.addEventListener("open", e => this.onOpen(e), false);

    this.source.addEventListener("error", e => this.onError(e), false);

    // Add here (only mozilla)
    main();
    // Add here

  }
  StartRetrieveLiveData();

我需要使用 ajax 回调吗?我是 SSE 的新手,我正在努力让所有组件都正确吗?优先将加速度计数据(sensorValue)从 Onmsg 传递到函数 main(),这样模型就可以相应地在浏览器上实时移动,而不会出现任何错误或警告。非常感谢。

P.S,下面是我想要实现的

我们需要 sunMesh 在您的 main 方法范围之外或在全局范围内进行初始化,以便稍后访问它。

知道 sunMesh 必须在您的 main 方法中初始化才能访问它的位置,因此如果您不同步执行此操作(即加载模型),您可能会创建竞争条件。

let sunMesh;

function main() {
  sunMesh = new THREE.Mesh(...)
}

function onMsg(event) {
  const sensorValue = event.data;
  sunMesh.position.x = sensorValue;
}

// or, in the global scope (I'd try to avoid this)

function main() {
  window.sunMesh = new THREE.Mesh(...)
}

function onMsg(event) {
  const sensorValue = event.data;
  window.sunMesh.position.x = sensorValue;
}

编辑:由于您的消息事件是异步的,因此您必须在动画循环内部或 onMsg 函数内部进行渲染才能呈现更新(您可以对相机、场景和渲染器引用执行相同的操作,因为以上)。

let sunMesh;

function main() {

  const canvas = document.querySelector('#canvas');
  const renderer = new THREE.WebGLRenderer({ canvas });
  var context = canvas.getContext("2d");

  const fov = 70;
  const aspect = 2;
  const near = 20;
  const far = 500;
  const color = 0xFFFFFF;
  const intensity = 1;
  const size = 10;
  const divisions = 10;
  const objects = [];
  const radius = 3;
  const widthSegments = 3;
  const heightSegments = 3;
  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
  const sphereGeometry = new THREE.BoxGeometry(radius, widthSegments, heightSegments);
  const sunMaterial = new THREE.MeshBasicMaterial({ color: "green", wireframe: false });
  sunMesh = new THREE.Mesh(sphereGeometry, sunMaterial)
  const light = new THREE.PointLight(color, intensity);
  // const gridHelper = new THREE.GridHelper(200000, 10000);

  camera.position.z = 0;
  camera.position.x = 100;
  camera.up.set(0, 0, 1);
  camera.lookAt(0, 0, 0);   

  const scene = new THREE.Scene();
  {
    const color = 0x00afaf;
    const intensity = 10;
    const light = new THREE.PointLight(color, intensity);
    scene.add(light);
    // gridHelper.geometry.rotateY(Math.PI / 2);
    // scene.add(gridHelper);
    // scene.add(light);
  }
  function resizeRendererToDisplaySize() {
  const canvas = renderer.domElement;
  const width = canvas.clientWidth;
  const height = canvas.clientHeight;
  const needResize = canvas.width !== width || canvas.height !== height;
  if (needResize) {
    renderer.setSize(width, height, false);
  }
  return needResize;
}

function resizeToClient() {
  const needResize = resizeRendererToDisplaySize()
  if (needResize) {
    const canvas = renderer.domElement;
    camera.aspect = canvas.clientWidth / canvas.clientHeight;
    camera.updateProjectionMatrix();
  }
}

  var cubeAxis = new THREE.AxesHelper(10);
  sunMesh.add(cubeAxis);

  sunMesh.scale.set(5, 5, 5)
  scene.add(sunMesh);
  scene.background = new THREE.Color(0.22, 0.23, 0.22);

  function render() {
    renderer.render(scene, camera);
  }
  resizeToClient();
  requestAnimationFrame(render);
}


function onMsg(event) {
  // console.log(`[message] Data received from server: ${event.data}`);
  // console.log("event.data = " + JSON.parse(event.data));

  var received_msg = event.data;

  var obj = JSON.parse(JSON.parse(received_msg));
  if (obj !== null) {
    if (
      obj.hasOwnProperty("DataMapChangedObjectsAddressValue") &&
      obj["DataMapChangedObjectsAddressValue"][0]["DataMapAddress"] !==
      undefined
    ) {
      let sensorAddr =
        obj["DataMapChangedObjectsAddressValue"][0]["DataMapAddress"];
      let sensorValue =
        obj["DataMapChangedObjectsAddressValue"][0]["Value"];

      //Accelerometer X Axis
      //if(sensorAddr === this.despToAddrMap.get("Accelerometer X Axis Data")){
      if (sensorAddr === 3) {
        console.log((sensorValue / 16384) * 500);
      }

      sunMesh.position.x = sensorValue;
    }
  }
}

function onOpen(e) {
  console.log("SSE connected");
}

function onError(e) {
  // console.log(`[error] ${error.message}`);
  if (e.eventPhase == EventSource.CLOSED) this.source.close();
  if (e.target.readyState == EventSource.CLOSED) {
    console.log("SSE Disconnected");
  } else if (e.target.readyState == EventSource.CONNECTING) {
    console.log("SSE Connecting ...");
  }
}

function StartRetrieveLiveData() {
  if (!!window.EventSource) {
    this.source = new EventSource("/sse");
  } else {
    console.log("Your browser doesn't support SSE");
  }

  this.source.addEventListener("message", e => this.onMsg(e));

  this.source.addEventListener("open", e => this.onOpen(e), false);

  this.source.addEventListener("error", e => this.onError(e), false);

  // Add here (only mozilla)
  main();
  // Add here

}
StartRetrieveLiveData();