【问题标题】:JS SSE: Cannot access event.data outside of onMsg callback function?JS SSE:无法在 onMsg 回调函数之外访问 event.data?
【发布时间】:2021-03-15 00:51:20
【问题描述】:

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

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

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

下面是我的代码:

它只渲染 3D 模型(它是静态的),我可以在开发者工具窗口中看到 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,下面是我想要实现的

【问题讨论】:

    标签: javascript html server three.js server-sent-events


    【解决方案1】:

    我们需要将 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();

    【讨论】:

    • 但是 sunMesh.position.x 应该在函数 main() 内的函数 render() 内运行,所以我需要将来自 onMsg 的 sensorValue 提供回函数 render(),它没有你建议,解决这个问题的方法是什么?
    • 您必须将renderer.render(scene, camera) 移动到您的render 函数中,并让onMsg 函数更新网格的位置(您将删除渲染函数中的旧引用)。您也可以从 onMsg 函数进行渲染。
    • 您能举个例子吗?我认为我做得不对
    • 当然。我会在答案中添加一个 sn-p。
    • 谢谢,我会尽快试一试,成功后我会标记为答案
    猜你喜欢
    • 2021-01-11
    • 1970-01-01
    • 2020-07-31
    • 1970-01-01
    • 2016-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多