javascript - 如何分配异步函数中同步作用域中定义的变量?

标签 javascript node.js asynchronous

我正在尝试编写一个 GUI 前端,它使用服务来获取有关系统的数据。我使用 net.Socket 作为其客户端。我希望能够访问在其他模块的数据事件处理程序中分配的某些变量,但在回调函数完成后分配不会保留。

有问题的代码:

client.on('data', (data) => {
      var array = [...data];
      array.splice(0,2);
      for (var i=0;i<array.length;i++) {
        dataInBuffer = dataInBuffer + String.fromCharCode(array[i]);
      }
      console.log(dataInBuffer);
      if (dataInBuffer.startsWith('batStat')) {
        let lastBatteryJSON = JSON.parse(dataInBuffer.split(';')[1]);
        module.exports.hasBattery = lastBatteryJSON.hasBattery == 'true';
        module.exports.isCharging = lastBatteryJSON.isCharging == 'true';
        module.exports.lastBatteryReading = parseFloat(lastBatteryJSON.batteryLife);
      }
      dataInBuffer = '';
    });

这三个导出的变量赋值实际上不起作用,这些变量总是保持未定义状态或者在函数之外保持默认值。我尝试使用 Promise 来解决这个问题,但得到了相同的结果。我很茫然,找不到解决此问题的任何其他问题或论坛帖子。

编辑 我无法选择将依赖于这些变量的代码移动到回调中。为了做到这一点,我必须等待每一帧的数据并因此淹没服务器。

最佳答案

正如苹果评论的那样;您可以导出一个对象并在每次接收数据时改变它:

const data = {};
client.on('data', (data) => {
  var array = [...data];
  array.splice(0, 2);
  for (var i = 0; i < array.length; i++) {
    dataInBuffer = dataInBuffer + String.fromCharCode(array[i]);
  }
  console.log(dataInBuffer);
  if (dataInBuffer.startsWith('batStat')) {
    let lastBatteryJSON = JSON.parse(dataInBuffer.split(';')[1]);
    //mutate the data object
    data.hasBattery = lastBatteryJSON.hasBattery == 'true';
    data.isCharging = lastBatteryJSON.isCharging == 'true';
    data.lastBatteryReading = parseFloat(lastBatteryJSON.batteryLife);
  }
  dataInBuffer = '';
});
//export the data object
module.exports.batteryData = data;

或者,当 certainPerformance 回答时,您可以让调用者决定何时询问信息并提供 promise 。

这是一定性能答案的扩展版本,它也监听错误,因此可以拒绝 promise ,并在解决或拒绝 promise 时清理事件监听器:

//wrapper for client.on to add and remove event listeners
const listeners = (function(){
  var listenerCounter = -1;
  const listeners = [];
  const triggerEvent = event => data =>{
    listeners.filter(
      listener=>listener[2] === event
    ).forEach(
      listener=>listener[1](data)
    );
  };
  client.on('data', triggerEvent("data"));
  client.on('error', triggerEvent("error"));//assuming you have an error event
  return {
    add:(event,fn)=>{
      listenerCounter = listenerCounter + 1;
      if(listenerCounter>1000000){
        listenerCounter=0;
      }
      listeners.push([listenerCounter,fn,event]);
      return listenerCounter;
    },
    remove:num=>{
      listeners = listeners.filter(
        listener=>{
          num !== listener[0];
        }
      )
    }
  }
}());

//convert data to object or false
const getObjectFromData = data => {
  var array = [...data];
  var dataInBuffer="";
  array.splice(0,2);
  for (var i=0;i<array.length;i++) {
    dataInBuffer = dataInBuffer + String.fromCharCode(array[i]);
  }
  console.log(dataInBuffer);
  if (dataInBuffer.startsWith('batStat')) {
    let lastBatteryJSON = JSON.parse(dataInBuffer.split(';')[1]);
    return {
      hasBattery : lastBatteryJSON.hasBattery == 'true',
      isCharging : lastBatteryJSON.isCharging == 'true',
      lastBatteryReading : parseFloat(lastBatteryJSON.batteryLife)
    };
  }
  return false;
}

//export this function
const getBatteryData = () =>  
  new Promise((resolve,reject) => {
    const removeListeners = ()=>{
      listeners.remove(okId);
      listeners.remove(errorId);
    }
    const okId = listeners.add(
      "data",
      data=>{
        const resultObject = getObjectFromData(data);
        if(resultObject){
          resolve(data);
          removeListeners();//clean up listeners
        }else{
          //not sure of on data is triggered multiple times by client.on.data
          //  if it is then at what point do we need to reject the returned promise?
        }
      }
    )
    const errorId = listeners.add(
      "error",
      error=>{
        reject(error);
        removeListeners();//clean up listeners
      }
    )
  });

  //you can call getBatteryData like so:
  //getBatteryData()
  // .then(batteryData=>console.log(batteryData))
  // .catch(error=>console.warn("an error getting battery data:",error))

关于javascript - 如何分配异步函数中同步作用域中定义的变量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49889672/

相关文章:

javascript - 如何从异步调用返回响应?

javascript - JS Object Loop 返回 undefined,而 Lodash map 返回值

javascript - 如何在单个 JS 变量调用中使用多个字符串

javascript - 删除谷歌地图 iFrame 上的地址栏

javascript - Rails 页面加载模态背景两次?

node.js - 测试快速应用程序 API 的正确方法?

javascript - 将 Web token 从后端传递到前端(Node.js + Express 到 AngularJS)

javascript - 处理多个上传的文件 'synchroneously'

Node.js 聊天 - 存储 session.id 以供以后使用?

c# - 等待抽象函数完成 c#