为什么我无法在cordova应用程序中获得全球价值?

时间:2016-07-18 23:02:05

标签: javascript cordova

我将outputTagJson设置为cordova app对象的全局变量。但是,当我尝试在函数readDataBlock: function()中显示时,我无法显示整个JSON,只会收到一条消息并将被复制。如果我在onListeningData: function(data)中显示JSON,则数据正确且完整。我认为可能导致此问题的部分来自concat部分,其中我将每个响应与回车连接(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

2 个答案:

答案 0 :(得分:1)

您的问题是您的功能范围。当您尝试在app中使用app.something时,您将在app对象的范围内创建新的var app并使用它的.something。换句话说,当您尝试在对象内部使用对象名称时,您将创建具有相同名称的局部变量,该变量将在执行代码时覆盖全局变量。应始终避免在本地覆盖全局变量。

这里完美地解释了:How do JavaScript closures work?

答案 1 :(得分:0)

我同意@Teo在他的回答中所说的内容,所以我重构了我的代码,它现在有效。基本上,我还需要一个回调来包装我的局部变量和函数。

然后我在函数和main中分隔了我的代码:

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