我如何使用回调 return 来自 node.js 函数的值?

How do i return a value from a node.js function using a callback?

我是来自 vb.net 背景的 nodejs 新手。我看过很多使用回调的例子,但我就是不明白。很抱歉,如果这是非常基本的。

我正在编写一个 AWS Lambda 函数并尝试从 AWS IOT Thing Shadow 获取一个值并将其分配给一个变量。但是我无法让它工作,但是日志确实显示返回了该值。我知道它与 sync/async 有关,但不知道如何获得它。这是到目前为止的代码:

//determine doorstate
function getdoorstate() { 
    //ask the thing
    var currentstate;
        var paramsGet = {
        "thingName": "garagedoor1",
        };
    iotData.getThingShadow(paramsGet, function (err, data) {
        if (err) {
        console.log("Error : " + err, err.stack);
          } else {
    console.log(data.payload);
    var obj = JSON.parse(data.payload);
    currentstate=obj["state"]["reported"]["doorstate"];
    console.log("The function doorstate is: "+currentstate);
            }
       });
    }

var doorstate = getdoorstate();

日志显示控制台写入正常(假设它们发生在检索到数据之后):

INFO    {"state":{"desired":{"doorstate":0,"transitstate":0},"reported":{"doorstate":0,"transitstate":0}},"metadata":{"desired":{"doorstate":{"timestamp":1591241517},"transitstate":{"timestamp":1591241517}},"reported":{"doorstate":{"timestamp":1591241517},"transitstate":{"timestamp":1591241517}}},"version":444,"timestamp":1591241860}
The function doorstate is: 0

然而返回的值是:undefined

任何人都可以建议如何更改我的代码以正确使用回调。简单点——我是新来的! 谢谢!


根据 Sagar 建议的更新代码 - 仍然存在问题

//determine doorstate
function getdoorstate() { 
    //ask the thing
        var paramsGet = {
        "thingName": "garagedoor1",
        };
    iotData.getThingShadow(paramsGet, function (err, data) {
        if (err) {
        console.log("Error : " + err, err.stack);
          } else {
            callback(data)
            }
       });
    }
 getdoorstate(function (value){
     console.log(value);
 });
var doorstate = getdoorstate();

我又做错了什么?

getdoorState 函数有异步操作,如果你直接调用它,获取物联网的过程将在后台,它会开始执行下一行。

所以当你直接调用 getdoorstate() 时,它总是 return 未定义。您需要等待 api 调用以使用 callback, promises 或 async await

返回数据

你可以试试这样的

// using call back
function getdoorstate(callback) { 
    //ask the thing

    iotData.getThingShadow(paramsGet, function (err, data) {
        if (err) {
        console.log("Error : " + err, err.stack);
          } else {
            callback(data)
            }
       });
    }

 getdoorstate(function (value){
     console.log(value)
     // Access value here 
 });
 // Below line won't work
 var value = getdoorstate()



// using promises
 function getdoorstate(callback) { 
    return new Promise((resolve, reject) => {
        //ask the thing

        iotData.getThingShadow(paramsGet, function (err, data) {
            if (err) 
                reject(err)
            else 
                resolve(data)
        });
        }
    })

 getdoorstate()
 .then(data => {
    console.log(data)
 })
 .catch(err=>{
     console.log(data)
 })

基于 Sagar 的上述帮助,我现在已经能够在 nodejs 中了解回调、承诺和等待。 (好吧,反正我是这么认为的。)下面的代码片段现在是从我的 Lambda 函数中提取的一个工作示例。其余代码仅基于 Github 或 AWS 上可用的示例。

我的解决方案是对一部分使用回调,对 Alexa 处理程序代码中的代码使用 async/promise/await。这可能现在可以简化为更简单的代码,因此代码不会在每个处理程序中重复,但对于它的价值,我希望下面的代码能帮助其他一些 nodejs 和 AWS IOT/Alexa 的新手弄清楚如何获得Lamda 等待从物联网事物影子中获取所需的值。

// more code above ...(see ASK and AWS samples)

//IOT Stuff - settings
AWS.config.region = "<put your own region in here>";
var IOT_Data = new AWS.IotData({
    endpoint: "<put your IOT Shadow Endpoint in here>"
});
var IOT_Thing = {
    "thingName": "<put the name of your thing here>"
};
var doorstate; //this is used to hold the part of JSON data I want 

//additional functions
//get shadow of thing using a call back.  this function uses a nodejs callback 
function getdoorstate(callback) {
    IOT_Data.getThingShadow(IOT_Thing, function(err, data) {
        if (err) {
            console.log("Error : " + err, err.stack);
        } else {
            callback(data);
        }
    });
}

//..more code in here.. not shown in this snippet

//this is one of the Alexa intent handlers

// core functionality
const DoorStateHandler = {
    canHandle(handlerInput) {
        const request = handlerInput.requestEnvelope.request;
        // checks request type - this one handes an intent with name of doorState
        return request.type === 'IntentRequest' &&
            request.intent.name === 'doorState';
    },
// important to use the async here to get the code to wait for the 'promise' (uses nodejs promise and await)
    async handle(handlerInput) {
        var speakOutput = "Let me check..."; /set a var ready for the speech to send back to Alexa
        //set up a promise so that we can get the value I need from the thing shadow
    let promise = new Promise((resolve, reject) => {
            getdoorstate(function(value) {
                var obj = JSON.parse(value.payload); //parse to json
                doorstate = obj["state"]["reported"]["doorstate"]; //return just the value of the doorstate
                console.log("The doorstate is: " + doorstate);
                speakOutput = speakOutput.concat(msg[doorstate]); //concatenate this to the var containing the speech
                resolve(speakOutput); //resolve the promise and return the speech
            });
        });
        //return result
    // this is important - use the await here so that we dont proceed any further until the promise is resolved with the thing values
        let result = await promise; 
        return handlerInput.responseBuilder
            .speak(result)
            .withSimpleCard("Garage Door", result)
            .getResponse();
    },
};

// this is another handler for sending a desired action to the IOT shadow 
const DoorTransitHandler = {
    canHandle(handlerInput) {
        const request = handlerInput.requestEnvelope.request;
        // checks request type
        return request.type === 'IntentRequest' &&
            request.intent.name === 'activate_door';
    },
    //again use async so that we can use promise and await - all the rest like above..
    async handle(handlerInput) {
        var speakOutput = "I'm on it...";
        let promise = new Promise((resolve, reject) => {
            getdoorstate(function(value) {
                var obj = JSON.parse(value.payload);
                doorstate = obj["state"]["reported"]["doorstate"];
                console.log("The doorstate is: " + doorstate);
                speakOutput = speakOutput.concat(msg[doorstate]);
                resolve(speakOutput);
            });
        });
        //return result
        let result = await promise;
        // set output
        result += "I'll push the button for you. ";

    //build the json to send back to the IOT shadow to get the thing to do something
        var paramsUpdate = {
            "topic": "$aws/things/garagedoor1/shadow/update",
            "payload": '{"state":{"desired":{"doorstate":0,"transitstate":1}}}',
            "qos": 0
        };
    //now here we send our desired action back to the IOT Thing Shadow
        IOT_Data.publish(paramsUpdate, function(err, data) {
            if (err) console.log(err, err.stack); // an error occurred
            else console.log(data.payload); // successful response
        });

        // return response by means of Alexa
        return handlerInput.responseBuilder
            .speak(result)
            .getResponse();
    },
};

// and the code continues...  (see ASK and AWS samples)