使用回调中的变量作为全局变量

时间:2018-08-16 13:28:57

标签: javascript asynchronous callback blockly google-blockly

我做了一个块,其中出现了对指定URL的请求。

在此块中,我可以使用来自响应的数据,但是在此块之外,由于异步,我无法获取此数据。

是否可以通过块或其他方式模拟同步请求,将接收到的数据保存到全局变量中?

enter image description here

已创建块的代码:

Blockly.Blocks['request'] =
'<block type="request">'
+ '     <value name="URL">'
+ '         <shadow type="text">'
+ '             <field name="TEXT">text</field>'
+ '         </shadow>'
+ '     </value>'
+ '     <value name="LOG">'
+ '     </value>'
+ '     <value name="WITH_STATEMENT">'
+ '     </value>'
+ '     <mutation with_statement="false"></mutation>'
+ '</block>';

Blockly.Blocks['request'] = {
init: function() {
    this.appendDummyInput('TEXT')
        .appendField('request');

    this.appendValueInput('URL')
        .appendField('URL');

    this.appendDummyInput('WITH_STATEMENT')
        .appendField('with results')
        .appendField(new Blockly.FieldCheckbox('FALSE', function (option) {
            var delayInput = (option == true);
            this.sourceBlock_.updateShape_(delayInput);
        }), 'WITH_STATEMENT');

    this.appendDummyInput('LOG')
        .appendField('log level')
        .appendField(new Blockly.FieldDropdown([
            ['none',  ''],
            ['info',  'log'],
            ['debug', 'debug'],
            ['warning',  'warn'],
            ['error', 'error']
        ]), 'LOG');

    this.setInputsInline(false);
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);

    this.setColour(230);
    this.setTooltip('Request URL');
    this.setHelpUrl('https://github.com/request/request');
},
mutationToDom: function() {
    var container = document.createElement('mutation');
    container.setAttribute('with_statement', this.getFieldValue('WITH_STATEMENT') === 'TRUE');
    return container;
},
domToMutation: function(xmlElement) {
    this.updateShape_(xmlElement.getAttribute('with_statement') == 'true');
},
updateShape_: function(withStatement) {
    // Add or remove a statement Input.
    var inputExists = this.getInput('STATEMENT');

    if (withStatement) {
        if (!inputExists) {
            this.appendStatementInput('STATEMENT');
        }
    } else if (inputExists) {
        this.removeInput('STATEMENT');
    }
}};

Blockly.JavaScript['request'] = function(block) {
var logLevel = block.getFieldValue('LOG');
var URL = Blockly.JavaScript.valueToCode(block, 'URL', Blockly.JavaScript.ORDER_ATOMIC);
var withStatement = block.getFieldValue('WITH_STATEMENT');

var logText;
if (logLevel) {
    logText = 'console.' + logLevel + '("request: " + ' + URL + ');\n'
} else {
    logText = '';
}

if (withStatement === 'TRUE') {
    var statement = Blockly.JavaScript.statementToCode(block, 'STATEMENT');
    if (statement) {

        var xmlhttp = "var xmlHttp = new XMLHttpRequest();";
        var xmlopen = "xmlHttp.open('POST', " + URL + ", true);";
        var xmlheaders = "xmlHttp.setRequestHeader('Content-type', 'application/json');\n" + 
                         "xmlHttp.setRequestHeader('Authorization', 'Bearer psokmCxKjfhk7qHLeYd1');";
        var xmlonload = "xmlHttp.onload = function() {\n" +
                        "  console.log('recieved:' + this.response);\n" +
                        "  var response = this.response;\n" +
                        "  var brightness = 'brightness: ' + JSON.parse(this.response).payload.devices[0].brightness;\n" +
                        "  " + statement + "\n" +
                        "}";

        var json = JSON.stringify({
            "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
            "inputs": [{
                "intent": "action.devices.QUERY",
                "payload": {
                    "devices": [{
                        "id": "0",
                        "customData": {
                            "smartHomeProviderId": "FkldJVJCmDNSaoLkoq0txiz8Byf2Hr"
                        }
                    }]
                }
            }]
        });

        var xmlsend = "xmlHttp.send('" + json + "');";

        var code = xmlhttp + '\n' + xmlopen + '\n' + xmlheaders + '\n' + xmlonload + '\n' + xmlsend;
        return code;

    } else {

        var xmlhttp = "var xmlHttp = new XMLHttpRequest();";
        var xmlopen = "xmlHttp.open('POST', " + URL + ", true);";
        var xmlheaders = "xmlHttp.setRequestHeader('Content-type', 'application/json');\n" + 
                         "xmlHttp.setRequestHeader('Authorization', 'Bearer psokmCxKjfhk7qHLeYd1');";
        var xmlonload = "xmlHttp.onload = function() {\n" +
                        "  console.log('recieved:' + this.response);\n" +
                        "}";

        var json = JSON.stringify({
            "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
            "inputs": [{
                "intent": "action.devices.QUERY",
                "payload": {
                    "devices": [{
                        "id": "0",
                        "customData": {
                            "smartHomeProviderId": "FkldJVJCmDNSaoLkoq0txiz8Byf2Hr"
                        }
                    }]
                }
            }]
        });

        var xmlsend = "xmlHttp.send('" + json + "');";

        var code = xmlhttp + '\n' + xmlopen + '\n' + xmlheaders + '\n' + xmlonload + '\n' + xmlsend;
        return code;
    }
} else {
        var xmlhttp = "var xmlHttp = new XMLHttpRequest();";
        var xmlopen = "xmlHttp.open('POST', " + URL + ", true);";
        var xmlheaders = "xmlHttp.setRequestHeader('Content-type', 'application/json');\n" + 
                         "xmlHttp.setRequestHeader('Authorization', 'Bearer psokmCxKjfhk7qHLeYd1');";
        var xmlonload = "xmlHttp.onload = function() {\n" +
                        "  console.log('recieved:' + this.response);\n" +
                        "}";

        var json = JSON.stringify({
            "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
            "inputs": [{
                "intent": "action.devices.QUERY",
                "payload": {
                    "devices": [{
                        "id": "0",
                        "customData": {
                            "smartHomeProviderId": "FkldJVJCmDNSaoLkoq0txiz8Byf2Hr"
                        }
                    }]
                }
            }]
        });

        var xmlsend = "xmlHttp.send('" + json + "');";

        var code = xmlhttp + '\n' + xmlopen + '\n' + xmlheaders + '\n' + xmlonload + '\n' + xmlsend;
        return code;
}};

2 个答案:

答案 0 :(得分:2)

实际上,我们在Blockly环境中广泛使用Promises。我的建议是对此作出承诺,然后使用generator function。例如,我们使用co库包装我们生成的代码,然后对异步值使用yield语句使它们同步运行。例如:

对于类似于此的块设置-

A variable block setting a variable called getUsername to the value from the DB, Logged In User Record in User Name, then toasting the user about it

生成的代码将是这样的(简化)-

co(function* () {
    var getUsername;
    // getFieldValue makes an asynchronous call to our database
    getUsername = (yield getFieldValue("username", "my user record Id", "users"));
    Promise.all(inputPromises)
    let inputPromises = [];
    inputPromises.push('User name is');
    inputPromises.push(getUsername);

    yield new Promise(function(resolve, reject) {
        Promise.all(inputPromises).then(function(inputResults) {
            let [TITLE, MESSAGE] = inputResults;
            let activity = "toastMessage";
            let LEVEL = "success";
            try {
                var params = {message: MESSAGE, title: TITLE, level: LEVEL};
                interface.notification(params);
                return resolve();
            } catch(err) {
                return reject(err);
            }

        }).catch(reject);

    });
    return true;
}

但是,正如您可能已经注意到的那样,这并不总是像在区块之前粘贴“收益率”那样容易。根据您的设置,您可能需要使用Promise.all来发挥更大的创造力,以获取块中的值,依此类推。(实际上,我们最终编辑了一堆Blockly核心块,以将'yield'附加在具有为了使这项工作有效,请在其输出类型中设置“承诺”类型,但是根据您的设置,这可能会过大。)

显然,您需要确保已将其编译或运行在支持ES6的环境中。

当然,一旦您进入异步设置,实际上并没有任何回头作用-协同函数本身会返回Promise,因此您需要适当地处理它。但总的来说,我们发现这是一个非常强大的解决方案,我们很乐意帮助您更详细地了解它。

答案 1 :(得分:1)

通过使用JS解释器(docsGitHub),可以方便地由创建Blockly的同一个人编写的代码块具有无承诺,async函数或回调的异步执行。 JS Interpreter是JavaScript-in-JavaScript实现。这确实意味着需要大量代码才能将主JS VM的功能/命令连接到解释器的嵌入式实现。

Blockly进行了一些演示(src)。特别是,您将要研究async-execution.html和wait块的实现。您可以找到实时运行的here等待块。

为方便起见,解释器的外部API文档部分恰好使用XMLHttpRequest作为其示例实现。对于您的请求块的实现,这应该是一个很好的起点。

相关问题