Scoping of variables in nodeJS in callback functions - node.js

This is a nodeJS code nugget from my application, written for publishing in AWS Lambda. The callProcess function basically returns some processed information about the city I am passing - hard coded here for "New York"
function speech2(intent, session, callback) {
let country;
const repromptText = null;
const sessionAttributes = {};
let shouldEndSession = false;
let speechOutput = 'old text';
callProcess('New York', function (error, data) {
if (!error) {
speechOutput = data;
console.log(speechOutput);
}
else {
console.log(error.message);
}
});
// Setting repromptText to null signifies that we do not want to reprompt the user.
// If the user does not respond or says something that is not understood, the session
// will end.
callback(sessionAttributes,
buildSpeechletResponse(intent.name, speechOutput, repromptText,
shouldEndSession));
}
The console.log(speechOutput) correctly displays the processed information about the city - i.e. callProcess has worked. However the callback at the end of this function that has speechOutput is still referring to 'old text' i.e. I am unable to over-write the variable using the processed information that sits within the function? How do I do this within callbacks?
Any help here is greatly appreciated. Thanks in advance.

your callProcess function is an async function which correctly shows the speechOutput data. The callback you've wriiten is outside this callProcess function which is called before callProcess is executed.
you can get the correct value of speechOutput by calling the callback inside your callProcess function.
like this-`
callProcess('New York', function (error, data) {
if (!error) {
speechOutput = data;
console.log(speechOutput);
callback(sessionAttributes,
buildSpeechletResponse(intent.name, speechOutput, repromptText,
shouldEndSession));
}
else {
console.log(error.message);
}
});
for further info how async method behave have a look at this async and sync functions

Related

redux-sagas does not dispatch action when firebase cloud function is complete

this function calls firebase cloud function
function createUser (data3){
var addUser = firebase.functions().httpsCallable('crearPaquete');
addUser(data3).then(function(result) {
// Read result of the Cloud Function.
return result //return uid inserted
}).catch(function(error) {
// Getting the Error details.
var code = error.code;
var message = error.message;
var details = error.details;
// ...
});
}
then I call function createUser inside redux-saga function
export function* createPackageStart({payload}){
try {
yield user= **createUser(payload)**
if(user.data){
yield put(createPackageSuccess()). **///this never is dispatch**
}
} catch(error){
yield put(createPackageFailure(error))
}
}
I need the result of cloud function to dispatch success action but "user" variable never gets update with cloud function result
How can I achieve this purpose?
It looks like your addUser function performs an asynchronous operation. With your current code, Cloud Functions terminates the container for your code when the last } has executed, which is before the asynchronous function has completed. To make the container wait, you need to return a promise.
function createUser(data3) {
var addUser = firebase.functions().httpsCallable('crearPaquete');
return addUser(data3).then(function(result) {
// Read result of the Cloud Function.
return result //return uid inserted
}).catch(function(error) {
// Getting the Error details.
var code = error.code;
var message = error.message;
var details = error.details;
// ...
});
}
For more on this, see the Firebase documentation on sending back the result

NodeJS return not stopping the entire function

I have the function, enter, that contains two fs.readFile functions inside and on the innermost readfile I'm checking to see whether a txt file contains a certain keyword, and if it does it should stop the entire enter function.
Her is what the enter function looks like:
async function enter(email, firstName, lastName){
fs.readFile(fileName, function(err, data){
parsedData = JSON.parse(data);
email = parsedData.email;
fs.readFile('./anotherfile.txt', function (err, data) {
if (err) throw err;
if(data.includes(email)){
console.log('Stopping function');
return;
}
});
});
console.log('Continuing with function');
}
The problem is that when anotherfile.txt contains the keyword, it does not stop the entire function, it continues and logs, "Continuing with function" as seen in the code above.
Any help would be appreciated!
fs promises are available Node v11.0.0
or You can can convert like this const readFile = util.promisify(fs.readFile);
const fsp = require('fs').promises;
async function enter(email, firstName, lastName) {
try {
let data = await fsp.readFile(fileName)
let parsedData = JSON.parse(data);
let email = parsedData.email;
data = await fsp.readFile('./anotherfile.txt')
if (data.includes(email)) {
console.log('Stopping function');
return;
}
console.log('Continuing with function');
} catch (err) {
throw err
}
}
This is because of two things.
You are using asynchronous File read, that is, the flow of code won't stop when this readFile is called. Instead, the program would keep executing in a normal fashion. And when the file read operation is completed, the callback function you supplied will be called with the corresponding error or data.
The return statement is inside of the callback function, hence it will only affect that function.
You need to use await when you are dealing with asynchronous functions. Look that up here

stub a function with callback, don't return promise

I have a service which is calling a function, I am writing a test for that service and I need to stub the function inside that service, that function has callback instead of returning a promise. when I make the stub for that I and give dummy return but it hangs as service expects the callback,
here is my code for the test
describe('Testing Token Service', () => {
let _stub =null;
beforeEach(async()=>{
_stub = sinon.stub(tModel.prototype, "save")
})
afterEach(async()=>{
if(_stub){
_stub.restore()
}
})
it('testing function saveToken_mongo() ', (done) => {
_stub.returns(Promise.resolve( {'status' : 'true'} ))
token_service.saveToken_mongo({},function(err, data){
console.log(err, data)
done();
})
// done()
}); });
and here is the service function for which I am writing test
Service.prototype.saveToken_mongo = function(token, callback){
var _token = new tModel( token ) ;
_token.save(function(err, data){
if(err){
callback(err, null);
return ;
}
else{
callback(null, {'status':true})
return ;
}
}) }
I need to make dummy callback return from that function using stub.
stub.returns is used for ordinary function not for callback. Since save is callback function, we can use yields.
_stub.yields(null, {'status' : 'true'});
The first argument is for error value, and the second one is for data.
As reference:
https://sinonjs.org/releases/v7.1.1/stubs/#stubyieldsarg1-arg2-
It's a bit tricky, your callback is the saveToken_mongo param,
didn't test it but try:
_stub.returns(function(err, data){callback(null, {'status':true}) });
let me know if you got an error for the callback, you may try using this.callback instead
After the study, I reached the conclusion that there are 2 solutions to this problem.
1) according to deerawan we can use yields to replace callback of function, like this
_stub.yields(null, {'status' : 'true'});
for more detail https://sinonjs.org/releases/v7.1.1/stubs/#stubyieldsarg1-arg2-
2) use bluebird to promisify all methods which will change all methods response from the callback to promise then you can use Promise.returns, here is code
var Model = conn.model( name , ModelSchema);
var Promise = require('bluebird');
Promise.promisifyAll(Model);
Promise.promisifyAll(Model.prototype);
module.exports = Model;
Now you can use test as follows
let _stub = null;
var tModel = require('./../app/models/tokens') ;
beforeEach(async()=>{
_stub = sinon.stub(tModel.prototype, "save")
})
afterEach(async()=>{
if(_stub){
_stub.restore()
}
})
it('returns a Promise' ,async function(){
_stub.returns(Promise.resolve( {'status' : 'true & false'} ));
expect(token_service.saveToken_mongo({})).to.be.a("Promise")
})

Alexa API skill - nodejs get request not executing

I'm working on my first Alexa skill and, as a starting point, would like Alexa to state data retrieved from a simple GET request (see lambda function below). For some reason, however, the request does not actually seem to be executing - nothing from inside request.get() is printing to the console and speechOutput is 'Outside Request' after the handler executes. I'm also new to looking through CloudWatch logs and have not been able to find any information about the network requests to even know if this is being attempted. Any help here would be welcome!
'use strict';
//Required node packages
const alexa = require('./node_modules/alexa-sdk');
const request = require('request');
// var https = require('https')
//this is the handler, when the lambda is invoked, this is whats called
exports.handler = function (event, context, callback) {
const skill = alexa.handler(event, context);
skill.appId = '<app_id>';
skill.registerHandlers(handlers);
skill.execute();
};
//Alexa handlers
const handlers = {
'LaunchRequest': function () {
console.log("inside of LaunchRequest");
const speechOutput = "Hello from NASA!";
this.response.speak(speechOutput).listen(speechOutput);
this.emit(':responseReady');
},
//Entering our main, part finding function
'GetAPOD': function () {
const intent_context= this
const speechOutput = getData()
intent_context.response.speak(speechOutput).listen(speechOutput);
intent_context.emit(':responseReady');
},
'Unhandled': function (){
console.log("inside of unhandled");
const speechOutput = "I didn't understand that. Please try again";
this.response.speak(speechOutput).listen(speechOutput);
this.emit(':responseReady');
}
};
const getData = function() {
const url = "https://api.nasa.gov/planetary/apod?api_key=<key>"
console.log("inside get data")
request.get(url, function (error, response, body) {
console.log("inside request")
console.log('error', error) //Print the error if one occurred
console.log('statusCode:', response && response.statusCode); // Print the response status code if a response was received
console.log('body:', body); // Print the HTML for the Google homepage.
return "complete request"
return body
});
return "outside request"
}
I have found in the past that such API requests will get clobbered because they are not synchronous, like David stated. To resolve this, I have had to tuck the request in a promise to get it to resolve, something similar to this in your case:
Change your function to contain the promise:
function getData = function() {
const url = "https://api.nasa.gov/planetary/apod?api_key=<key>"
console.log("inside get data")
return new Promise(function(resolve, reject) {
request.get(url, function (error, response, body) {
if (err) {
reject(err);
}
if (body) {
resolve(JSON.parse(body));
}
});
});
}
Then change your intent handler to use the promise:
//Entering our main, part finding function
'GetAPOD': function () {
getData()
.then(function(body) {
let speechOutput = body;
intent_context.response.speak(speechOutput).listen(speechOutput);
intent_context.emit(':responseReady');
}
Something along these lines. You would need to play with it a bit to make sure the results are produced as you intend. Hope this helps.
D

Async function in wit actions

I am currently developing a bot using wit.ai. I am quite new to node.js. Basically, I am following the guide provided by node-wit lib. I construct my wit object by:
const wit = new Wit({
accessToken: WIT_TOKEN,
actions,
logger: new log.Logger(log.INFO)
});
In my actions, I have something like:
const actions = {
send({sessionId}, {text}) {
//my sending action goes here.
},
firstaction({context, entities,sessionId}) {
var data = async_function();
context.receiver = data;
return context;
}
}
The issue is that whatever comes after async_function will be executed first. I tried to let async_function return a promise. However, this wouldn't work since whatever comes after my first action in node-wit library will be executed first without waiting for the context to return. I don't want to modify the node-wit library.
Any idea that would solve my issue is appreciated!
you can use async library for asynchronous call
https://caolan.github.io/async/docs.html
const async = require('async')
const actions = {
send({sessionId}, {text}) {
//my sending action goes here.
},
firstaction({context, entities,sessionId}) {
async.waterfall([function(callback) {
var d = async_function();
// if err pass it to callback first parameter
// return callback(err)
callback(null,d);
}], function(err, result) {
if(err) {
return err;
}
var data = result;
context.receiver = data;
return context;
})
}
}

Resources