2016-07-18 18 views
0

私はcordobaアプリオブジェクトのグローバル変数としてoutputTagJsonを設定しています。しかし、私はJSON全体を表示する際に、機能readDataBlock: function()で表示しようとしましたが、1つのメッセージだけが受信され、複製されます。 onListeningData: function(data)の中にJSONを表示すると、データは正確で完全です。私はこの問題を引き起こす可能性のある部分は、各応答をキャリッジリターン(ASCIIコード= 13)と連結する連結部分からのものだと考えています。しかし、私はこの問題に遭遇する機会はなかった。実際には、私の問題はより一般的なものとして記述することができると思います。私はjavascriptでグローバル変数を設定しましたが、一部の関数スコープから完全な値を取得できません。コーデバーアプリケーションでグローバル値を取得できないのはなぜですか?

var app = { 
    macAddress: "00:0B:CE:07:36:AB", // get your mac address from bluetoothSerial.list 
    chars: "", 
    responseGroup: [], 
    responseHeader: [''], 
    outputTagJson: {}, 
    timeList: [], 
    Execution_List: ['M,0\rU,18\rGR\rG,LOCATE,04,0,1,3\rO,2,30,0,0\rR,8\rS,2\rM,433\r'], 

/* 
    Application constructor 
*/ 
    initialize: function() { 
     this.bindEvents(); 
     console.log("Starting SimpleSerial app"); 
    }, 
/* 
    bind any events that are required on startup to listeners: 
*/ 
    bindEvents: function() { 
     document.addEventListener('deviceready', this.onDeviceReady, false); 
     connectButton.addEventListener('touchend', app.Connect, false); 
     scanButton.addEventListener('touchend', app.disCover, false); 
    }, 

/* 
    this runs when the device is ready for user interaction: 
*/ 
    onDeviceReady: function() { 
     // check to see if Bluetooth is turned on. 
     // this function is called only 
     //if isEnabled(), below, returns success: 

     var listPorts = function() { 
      // list the available BT ports: 
      bluetoothSerial.list(
       function(results) { 
        app.display(JSON.stringify(results)); 
       }, 
       function(error) { 
        app.display(JSON.stringify(error)); 
       } 
      ); 
     }; 

     // if isEnabled returns failure, this function is called: 
     var notEnabled = function() { 
      app.display("Bluetooth is not enabled.") 
     }; 

     // check if Bluetooth is on: 
     bluetoothSerial.isEnabled(
      listPorts, 
      notEnabled 
     ); 
    }, 

    disCover: function() { 
     var scan = function() { 
      app.clear(); 
      app.display("Scanning available Devices..."); 

      bluetoothSerial.discoverUnpaired(
       function(results) { 
        app.display(JSON.stringify(results)); 
       }, 
       function(error) { 
        app.display(JSON.stringify(error)); 
       } 
      ); 
     }; 

     var notEnabled = function() { 
      app.display("Bluetooth is not enabled.") 
     }; 

     bluetoothSerial.isEnabled(
      scan, 
      notEnabled 
     ); 

    }, 

/* 
    Connects if not connected, and disconnects if connected: 
*/ 
    Connect: function() { 

     // connect() will get called only if isConnected() (below) 
     // returns failure. In other words, if not connected, then connect: 
     var connect = function() { 
      // if not connected, do this: 
      // clear the screen and display an attempt to connect 
      app.clear(); 
      app.display("Attempting to connect. " + 
       "Make sure the serial port is open on the target device."); 
      app.display("Connected to: " + app.macAddress); 
      connectButton.innerHTML = "Disconnect"; 
      // attempt to connect: 
      bluetoothSerial.connect(
       app.macAddress, // device to connect to 
       app.connectSuccess, // start listening if you succeed 
       app.showError // show the error if you fail 
      ); 
     }; 

     // disconnect() will get called only if isConnected() (below) 
     // returns success In other words, if connected, then disconnect: 
     var disconnect = function() { 
      app.display("attempting to disconnect"); 
      // if connected, do this: 
      bluetoothSerial.disconnect(
       app.closePort,  // stop listening to the port 
       app.showError  // show the error if you fail 
      ); 
     }; 

     // here's the real action of the manageConnection function: 
     bluetoothSerial.isConnected(disconnect, connect); 
    }, 
/* 
    subscribes to a Bluetooth serial listener for newline 
    and changes the button: 
*/ 

    getBatteryInfo: function() { 
     var Bcomm = 'WB\r'; 
     app.writeCommand(Bcomm); 
    }, 

    // On Connection Success, we want to display battery info 
    // and send command immediately 
    connectSuccess: function() { 
     app.getBatteryInfo(); 
     for (var i = 0; i < app.Execution_List.length;i++) 
     { 
      (function(n) { 
       app.writeCommand(app.Execution_List[n]); 
      })(i); 
     } 
    }, 

    // Wrapper of bluetooth write, read reponse immediately 
    // after sending commands 
    writeCommand: function(data) { 
     bluetoothSerial.write(data, 
      function(data) { 
       console.log('sending %s',data); 
     }, function(error){ 
      console.log(error); 
     }); 
     app.readDataBlock(); 
     app.responseGroup = []; 
    }, 

/* 
    Processor part: 
    Parsing Response String and out a JSON of each Attributes 
*/ 
    onParsing: function(data){ 
     var alphabeticRegex = /^[A-Z]+$/i;   // Response header start with an alphabetic string 
     var decimalRegex = /^\d+\.?\d*$/; 
     app.outputTagJson = {}; 
     if (data == null || data == '\r')   // Sanity Check 
     { 
      return; 
     } 
     Element = data.split(',');     
     while (true)        // For some response, it didn't start with 'A-z' 
     { 
      if (alphabeticRegex.test(Element[0]) != true) 
      { 
       Element.splice(0,1); 
      } 
      else 
      { 
       break; 
      } 
     } 
     // Parsing each options, not generic, have to deal with each specific case. 
     switch (Element[0]) { 
      case 'VV': 
       app.outputTagJson.readerIdentifier = {}; 
       app.outputTagJson.readerIdentifier.buildID = Element[2]; 
       app.outputTagJson.readerIdentifier.modelID = Element[3]; 
       break; 
      case 'V': 
       app.outputTagJson.Battery = {}; 
       app.outputTagJson.Battery.percentage = Element[2]; 
       if (Element[3] != null) 
       { 
        app.outputTagJson.Battery.chargingmode = "Charging"; 
       } 
       else 
       { 
        app.outputTagJson.Battery.chargingmode = "Not charged"; 
       } 
       break; 
      case 'U': 
       app.outputTagJson.timeStamp = {}; 
       app.outputTagJson.timeStamp.range = 10; 
       app.outputTagJson.timeStamp.range = 1.00; 
       break; 
      case 'M': 
       app.outputTagJson.readerMode = {}; 
       if (Element[1] == 0) app.outputTagJson.readerMode.message = 'Standby'; 
       if (Element[1] == 20) app.outputTagJson.readerMode.message = '303MHz'; 
       if (Element[1] == 40) app.outputTagJson.readerMode.message = 'Japanese 303MHz'; 
       if (Element[1] == 433) app.outputTagJson.readerMode.message = '433MHz'; 
       else app.outputTagJson.readerMode.message = 'In motion'; 
       break; 
      case 'H': 
       var len = Element.length; 
       var props = ['tagID','groupID','payload','timeStamp','sigStrenthA','sigStrenthB']; 
       app.outputTagJson.Tag = {}; 
       if (len >= 2) 
       { 
        app.outputTagJson.Tag[props[0]] = Element[1]; 
        app.outputTagJson.Tag.isLost = "False"; 
        for(var i=3;i<=len;i++) 
         app.outputTagJson.Tag[props[i-2]] = Element[i-1].slice(1,Element[i-1].length); 
       } 
       break; 
      case 'L': 
       var len = Element.length; 
       var props = ['tagID','groupID','payload','timeStamp']; 
       app.outputTagJson.Tag = {}; 
       if (len >= 2) 
       { 
        app.outputTagJson.Tag[props[0]] = Element[1]; 
        app.outputTagJson.Tag.isLost = "True"; 
        for(var i=3;i<=len;i++) 
         app.outputTagJson.Tag[props[i-2]] = Element[i-1].slice(1,Element[i-1].length); 
       } 
       break; 
      case 'E': 
       app.outputTagJson.Error = {}; 
       if (Element[1] == 2) app.outputTagJson.Error.message = "Received command is invalid"; 
       if (Element[1] == 3) app.outputTagJson.Error.message = "Command has too many parameters"; 
       if (Element[1] == 4) app.outputTagJson.Error.message = "A command parameter is out of range"; 
       if (Element[1] == 5) app.outputTagJson.Error.message = "Maximum number of group codes is exceeded"; 
       if (Element[1] == 6) app.outputTagJson.Error.message = "Character buffer is full. One or more tag reports were dropped"; 
       if (Element[1] == 7) app.outputTagJson.Error.message = "DSP offline. Indicates DSP failure or failed upgrade of DSP firmware"; 
       if (Element[1] == 8) app.outputTagJson.Error.message = "Access denied. Indicates security is enabled and a valid ':login' is required"; 
       break; 
      default: 
       break; 
     } 
    }, 

    // Listening to data, function will be continuous invoked 
    // until there's no more incoming data or unsubscribe/disconnect 
    // appears 
    onListeningData: function(data) { 
     var responseLine = []; 
     console.log('Receiving data from reader'); 
     // Convert raw data (binary arrays) to Unit8Array (ASCII code) 
     var bytes = new Uint8Array(data); 
     // Concat all integer until carriage return appears. 
     for (var i = 0; i< bytes.length; i++) 
     { 
      responseLine.push(bytes[i]); 
      if (bytes[i] == 13) 
      { 
       app.responseGroup.push(responseLine); 
       app.responseGroup = Array.prototype.concat.apply([],app.responseGroup); 
       responseLine = []; 
      } 
      else if (bytes[i] != 13 && i == bytes.length-1) 
      { 
       app.responseGroup.push(responseLine); 
      } 
     } 

     // Once we get the carriage return, parse it to string 
     // Do sanity check for null data and single carriage return 
     // single carraige return appears when <set-like> command is sent 
     // to the reader (a mark as <set-like> command success) 
     try { 
      var i = 0; 
      if (app.responseGroup.length > 0) 
      { 
       while (i<app.responseGroup.length) 
       { 
        if (app.responseGroup[i] == 13) 
        { 
         var strGroup = app.responseGroup.splice(0,i+1); 
         strGroup.splice(-1); 
         var response = String.fromCharCode.apply(null, strGroup); 
         app.onParsing(response); 
         //app.display(JSON.stringify(app.outputTagJson)); 
         i = 0; 
        } 
        else 
        { 
         i++; 
        } 
       } 
      } 
      else{ 
       throw err; 
      } 
     } catch(err) { 
      console.log(err); 
     } 
    }, 

    readDataBlock: function() { 
     // set up a listener to listen for newlines 
     // and display any new data that's come in since 
     // the last newline: 
     console.log('going to send data to the reader'); 
     //'M,0\rGR\rG,LOCATE,04,0,1,3\rO,2,30,0,0\rR,8\rS,2\rM,433\r' 
     //'G,LOCATE,04,0,0,0\rS,2\rO,1,0,0,2\rU,18\rN,0\rM,433\rZ,99,99\r' 
     bluetoothSerial.subscribeRawData(app.onListeningData, 
      function(error){ 
       console.log(error); 
     }); 
     if (JSON.stringify(app.outputTagJson) != "{}") 
      app.display(JSON.stringify(app.outputTagJson)); 
    }, 

/* 
    unsubscribes from any Bluetooth serial listener and changes the button: 
*/ 
    closePort: function() { 
     // if you get a good Bluetooth serial connection: 
     app.display("Disconnected from: " + app.macAddress); 
     // change the button's name: 
     connectButton.innerHTML = "Connect"; 
     // unsubscribe from listening: 
     bluetoothSerial.unsubscribe(
       function (data) { 
        app.display(data); 
       }, 
       app.showError 
     ); 
    }, 
/* 
    appends @error to the message div: 
*/ 
    showError: function(error) { 
     app.display(error); 
    }, 

/* 
    appends @message to the message div: 
*/ 
    display: function(message) { 
     var display = document.getElementById("message"), // the message div 
      lineBreak = document.createElement("p"),  // a line break 
      label = document.createTextNode(message);  // create the label 

     display.appendChild(lineBreak);   // add a line break 
     display.appendChild(label);    // add the message node 
    }, 
/* 
    clears the message div: 
*/ 
    clear: function() { 
     var display = document.getElementById("message"); 
     display.innerHTML = ""; 
    } 
};  // end of app 

答えて

1

問題はあなたの機能の範囲です。 app内のapp.somethingを使用しようとすると、appオブジェクトのスコープ内に新しいvar appが作成され、その中に.somethingが使用されます。言い換えれば、オブジェクト内でオブジェクト名を使用しようとすると、コードの実行時にグローバル変数をカバーする同じ名前のローカル変数が作成されます。グローバル変数をローカルで上書きすることは、常に避けなければなりません。

それは完全にここで説明しています:How do JavaScript closures work?

+0

はい、私はすでに私のコードをリファクタリングしました。残念なことに、それは主要な機能がこの状況の大きな低下になります。 –

+0

私はあなたにupvoteを与えますが、私は自分の解決策を受け入れます。 –

0

私は@Teoは彼の答えに言ったことに同意するが、私は私のコードをリファクタリングし、それが機能するようになりました。基本的には、ローカル変数と関数をラップするためにもう一度コールバックが必要です。

は、それから私は、機能とメインに私のコードを分離:

reader.js:

var reader = { 
    location_command: 'M,0\rU,18\rGR\rG,LOCATE,04,0,1,3\rO,2,30,0,0\rR,8\rS,2\rM,433\r', 
    tagLocation_callback: "", 

    getTagLocation: function(tagId,timeout,callback) { 
     console.log('in getTagLocation func') 
     reader.tagLocation_callback = callback; 
     reader.writeCommand(reader.location_command); 
     // Subscribe Raw Data 
     bluetoothSerial.subscribe(
      '\r', 
      reader.onListeningData, 
      function(error){ 
       console.log(error); 
     }); 
    }, 

    // Wrapper of bluetooth write, read reponse immediately 
    // after sending commands 
    writeCommand: function(command) { 
     console.log('sending %s', command[0]); 
     bluetoothSerial.write(command, 
      function(data) { 
       console.log('sent data %s',data); 
      }, function(error){ 
       console.log(error); 
     }); 
    }, 

    // Listening to data, function will be continuous invoked 
    // until there's no more incoming data or unsubscribe/disconnect 
    // appears 
    onListeningData: function(data) { 
     var outputTagJson = reader.onParsing(data); 
     reader.tagLocation_callback(outputTagJson); 
    }, 

    /* 
    Processor part: 
    Parsing Response String and out a JSON of each Attributes 
    */ 
    onParsing: function(data){ 
     data = data.slice(0,data.length-1); 
     var alphabeticRegex = /^[A-Z]+$/i;   // Response header start with an alphabetic string 
     var decimalRegex = /^\d+\.?\d*$/; 
     var outputTagJson = {}; 
     if (data == null || data == '\r')   // Sanity Check 
     { 
      return; 
     } 
     Element = data.split(','); 
     while (true)        // For some response, it didn't start with 'A-z' 
     { 
      if (alphabeticRegex.test(Element[0]) != true) 
      { 
       Element.splice(0,1); 
      } 
      else 
      { 
       break; 
      } 
     } 
     // Parsing each options, not generic, have to deal with each specific case. 
     switch (Element[0]) { 
      case 'VV': 
       outputTagJson.readerIdentifier = {}; 
       outputTagJson.readerIdentifier.buildID = Element[2]; 
       outputTagJson.readerIdentifier.modelID = Element[3]; 
       break; 
      case 'V': 
       outputTagJson.Battery = {}; 
       outputTagJson.Battery.percentage = Element[2]; 
       if (Element[3] != null) 
       { 
        outputTagJson.Battery.chargingmode = "Charging"; 
       } 
       else 
       { 
        outputTagJson.Battery.chargingmode = "Not charged"; 
       } 
       break; 
      case 'U': 
       outputTagJson.timeStamp = {}; 
       outputTagJson.timeStamp.range = 10; 
       outputTagJson.timeStamp.range = 1.00; 
       break; 
      case 'M': 
       outputTagJson.readerMode = {}; 
       if (Element[1] == 0) outputTagJson.readerMode.message = 'Standby'; 
       if (Element[1] == 20) outputTagJson.readerMode.message = '303MHz'; 
       if (Element[1] == 40) outputTagJson.readerMode.message = 'Japanese 303MHz'; 
       if (Element[1] == 433) outputTagJson.readerMode.message = '433MHz'; 
       else outputTagJson.readerMode.message = 'In motion'; 
       break; 
      case 'H': 
       var len = Element.length; 
       var props = ['tagID','groupID','payload','timeStamp','sigStrenthA','sigStrenthB']; 
       outputTagJson.Tag = {}; 
       if (len >= 2) 
       { 
        outputTagJson.Tag[props[0]] = Element[1]; 
        outputTagJson.Tag.isLost = "False"; 
        for(var i=3;i<=len;i++) 
         outputTagJson.Tag[props[i-2]] = Element[i-1].slice(1,Element[i-1].length); 
       } 
       break; 
      case 'L': 
       var len = Element.length; 
       var props = ['tagID','groupID','payload','timeStamp']; 
       outputTagJson.Tag = {}; 
       if (len >= 2) 
       { 
        outputTagJson.Tag[props[0]] = Element[1]; 
        outputTagJson.Tag.isLost = "True"; 
        for(var i=3;i<=len;i++) 
         outputTagJson.Tag[props[i-2]] = Element[i-1].slice(1,Element[i-1].length); 
       } 
       break; 
      case 'E': 
       outputTagJson.Error = {}; 
       if (Element[1] == 2) outputTagJson.Error.message = "Received command is invalid"; 
       if (Element[1] == 3) outputTagJson.Error.message = "Command has too many parameters"; 
       if (Element[1] == 4) outputTagJson.Error.message = "A command parameter is out of range"; 
       if (Element[1] == 5) outputTagJson.Error.message = "Maximum number of group codes is exceeded"; 
       if (Element[1] == 6) outputTagJson.Error.message = "Character buffer is full. One or more tag reports were dropped"; 
       if (Element[1] == 7) outputTagJson.Error.message = "DSP offline. Indicates DSP failure or failed upgrade of DSP firmware"; 
       if (Element[1] == 8) outputTagJson.Error.message = "Access denied. Indicates security is enabled and a valid ':login' is required"; 
       break; 
      default: 
       break; 
     } 
     return outputTagJson; 
    }, 

    unsubscribeTagLocation: function(callback){ 
     console.log("in unsubscribeTagLocation function "); 
     bluetoothSerial.unsubscribe(
      function(data){ 
       console.log(data); 
       callback("{message: 'tag location unsubscribed successfully!'}") 
      }, 
      function(error) { 
       console.log(error); 
      }); 
    }, 
}; 

app.js:

var app = { 
    macAddress: "00:0B:CE:01:A4:D7", // get your mac address from bluetoothSerial.list 
    //00:0B:CE:01:A4:D7 
    //"00:0B:CE:07:36:AB" 
    responseHeader: [''], 
    timeList: [], 

    /* 
    Application constructor 
    */ 
    initialize: function() { 
     this.bindEvents(); 
     console.log("Starting SimpleSerial app"); 
    }, 
    /* 
    bind any events that are required on startup to listeners: 
    */ 
    bindEvents: function() { 
     document.addEventListener('deviceready', this.onDeviceReady, false); 
     connectButton.addEventListener('touchend', app.Connect, false); 
     scanButton.addEventListener('touchend', app.disCover, false); 
    }, 

    /* 
    this runs when the device is ready for user interaction: 
    */ 
    onDeviceReady: function() { 
     // check to see if Bluetooth is turned on. 
     // this function is called only 
     //if isEnabled(), below, returns success: 

     var listPorts = function() { 
      // list the available BT ports: 
      bluetoothSerial.list(
       function(results) { 
        app.display(JSON.stringify(results)); 
       }, 
       function(error) { 
        app.display(JSON.stringify(error)); 
       } 
      ); 
     }; 

     // if isEnabled returns failure, this function is called: 
     var notEnabled = function() { 
      app.display("Bluetooth is not enabled.") 
     }; 

     // check if Bluetooth is on: 
     bluetoothSerial.isEnabled(
      listPorts, 
      notEnabled 
     ); 
    }, 

    disCover: function() { 
     var scan = function() { 
      app.clear(); 
      app.display("Scanning available Devices..."); 

      bluetoothSerial.discoverUnpaired(
       function(results) { 
        app.display(JSON.stringify(results)); 
       }, 
       function(error) { 
        app.display(JSON.stringify(error)); 
       } 
      ); 
     }; 

     var notEnabled = function() { 
      app.display("Bluetooth is not enabled.") 
     }; 

     bluetoothSerial.isEnabled(
      scan, 
      notEnabled 
     ); 

    }, 

    /* 
    Connects if not connected, and disconnects if connected: 
    */ 
    Connect: function() { 

     // connect() will get called only if isConnected() (below) 
     // returns failure. In other words, if not connected, then connect: 
     var connect = function() { 
      // if not connected, do this: 
      // clear the screen and display an attempt to connect 
      app.clear(); 
      app.display("Attempting to connect. " + 
       "Make sure the serial port is open on the target device."); 

      // attempt to connect: 
      bluetoothSerial.connect(
       app.macAddress, // device to connect to 
       app.connectSuccess, // start listening if you succeed 
       app.showError // show the error if you fail 
      ); 
     }; 

     // disconnect() will get called only if isConnected() (below) 
     // returns success In other words, if connected, then disconnect: 
     var disconnect = function() { 
      app.display("attempting to disconnect"); 
      // if connected, do this: 
      bluetoothSerial.disconnect(
       app.closePort,  // stop listening to the port 
       app.showError  // show the error if you fail 
      ); 
     }; 

     // here's the real action of the manageConnection function: 
     bluetoothSerial.isConnected(disconnect, connect); 
    }, 
    /* 
    subscribes to a Bluetooth serial listener for newline 
    and changes the button: 
    */ 

    /*getBatteryInfo: function() { 
     var Bcomm = 'WB\r'; 
     app.writeCommand(Bcomm); 
     if (JSON.stringify(app.outputTagJson) != "{}") 
     { 
      bluetoothSerial.unsubscribe(function(data) { 
        app.display(JSON.stringify(app.outputTagJson)); 
       }, 
       function(error) { 
        console.log(error); 
      }); 
      return; 
     } 
     bluetoothSerial.subscribe(
      '\r', 
      reader.onListeningData, 
      function(error){ 
       console.log(error); 
     }); 
    },*/ 

    displayResult: function(data){ 

     app.display("output message : "); 
     app.display(JSON.stringify(data)); 
    }, 

    // On Connection Success, we want to display battery info 
    // and send command immediately 
    connectSuccess: function() { 
     console.log("in connectSuccess"); 
     app.display("Connected to: " + app.macAddress); 
     connectButton.innerHTML = "Disconnect"; 
     reader.getTagLocation('00198525',10000, app.displayResult); 
     setTimeout(function(){ 
      reader.unsubscribeTagLocation(app.displayResult); 
     }, 5000); 

    }, 


    /* 
    unsubscribes from any Bluetooth serial listener and changes the button: 
    */ 
    closePort: function() { 
     app.clear(); 
     // if you get a good Bluetooth serial connection: 
     app.display("Disconnected from: " + app.macAddress); 
     // change the button's name: 
     connectButton.innerHTML = "Connect"; 
     // unsubscribe from listening: 
     bluetoothSerial.unsubscribe(
      function (data) { 
       app.display(data); 
      }, 
      app.showError 
     ); 
    }, 
    /* 
    appends @error to the message div: 
    */ 
    showError: function(error) { 
     app.display(error); 
    }, 

    /* 
    appends @message to the message div: 
    */ 
    display: function(message) { 
     var display = document.getElementById("message"), // the message div 
      lineBreak = document.createElement("p"),  // a line break 
      label = document.createTextNode(message);  // create the label 

     display.appendChild(lineBreak);   // add a line break 
     display.appendChild(label);    // add the message node 
    }, 
    /* 
    clears the message div: 
    */ 
    clear: function() { 
     var display = document.getElementById("message"); 
     display.innerHTML = ""; 
    } 
};  // end of app 
関連する問題