I've been having some trouble trying to output speech after getting data using request-reponse and processing it. For whatever reason in the callback function it wont output the text. The console.log(prompt) works yet it the response.say(prompt).shouldEndSession(false).send() doesn't. If you've any idea it'll be greatly appreciated.
test.getNumberStatus(number, function(err, message) {
console.log("In callback outside if statement");
if (err == null) {
console.log(message);
response.say(message).shouldEndSession(false).send();
} else {
console.log("Error");
rresponse.say(message).shouldEndSession(false).send();
}
});
stopInfo.prototype.getStopStatus = function(stopNumber, callback) {
var options = {
method: 'GET',
uri: ENDPOINT + '?stopid=' + stopNumber + '&maxresults=1&format=json',
json: true
};
requestPromise(options).then(function(stopStatusObject) {
if (true) { // check if error from dublin bus
console.log(stopStatusObject);
var template = _.template('busstopinfo <%= error %>');
var message = template({
'error': 'test'
});
callback(null, message);
}
}).catch(function(err) {
var message = "I didn\'t have data for stop number " + stopNumber;
callback(err, message);
});
};
I had a similar situation and found out resolve automatically sends your output which works for sync but not for async. Put add response.resolve in your troubled function to see if value is set to true before send(). If it is you already used the promise. I corrected mine by putting return in front of function name, following Asynchronous Handlers Example section from here
Related
I'm just getting started with hapi.js (^17.3.1) and mongodb (^3.0.7), and with asynchronous js code.
Inside a route handler, I'm trying to retrieve data from the database. As a test, I'm storing a string inside a variable "s" built by looping through database collection records. The expected output to the browser is
start dbInfo1 dbInfo2 dbInfoN end
I've tried various versions of this code:
module.exports = {
method: 'GET',
handler: async function (request, reply) {
return await getRoutes();
}
}
async function getRoutes() {
var s = "start";
const mongo = require('mongodb').MongoClient;
const mongoUrl = "mongodb://127.0.0.1:27017/";
return // I'm returning this whole thing because hapi.js says it wants a promise. (500 error)
await mongo.connect(mongoUrl)
.then(function(client) {
client.db("dbName").collection("collectionName")
.find({})
.forEach(function (record) {
console.log(record.item);
s += " | " + record.item;
});
s + " end"; // But I've tried placing "return" here (500 error)
});
// I've also tried ".then(function(s) { return s + 'end' }) here but it seems to only have the same set of options/problems manifest.
// I've also made it so that I place "return s + 'end'" here (displays "start end" with nothing in the middle).
}
I've tried placing the return statement in different places. I either get an http 500 error in the console
Debug: internal, implementation, error
Error: handler method did not return a value, a promise, or throw an error
dbInfo1
dbInfo2
dbInfoN
if I return the promise itself or from inside the promise, or I get
start end
in the browser if I return from outside the promise.
In either case, the console.log statement prints out the dbInfos output.
I've tried different placements, inclusions, and omissions of async and await with pretty much the same results. I've also tried wrapping what is being returned inside getRoutes into an explicit Promise using "new Promise(...". In this case, the console logs the dbInfos, but the browser hangs.
How do I await that "foreach" function before returning the variable s?
Without test, I can say the this is wrong:
return // I'm returning this whole thing because hapi.js says it wants a promise. (500 error)
await mongo.connect(mongoUrl)
.then(function(client) {
client.db("dbName").collection("collectionName")
.find({})
.forEach(function (record) {
console.log(record.item);
s += " | " + record.item;
});
s + " end"; // But I've tried placing "return" here (500 error)
});
return is parsed as return;
return await mongo.connect(mongoUrl)
.then(function(client) {
client.db("dbName").collection("collectionName")
.find({})
.forEach(function (record) {
console.log(record.item);
s += " | " + record.item;
});
s + " end"; // But I've tried placing "return" here (500 error)
});
is the correct way. Any linter would have warned you about it.
Finally! Got it working with this code:
module.exports = {
method: 'GET',
handler: function (request, reply) {
return getRoutes();
}
}
function getRoutes() {
const mongo = require('mongodb').MongoClient;
const mongoUrl = "mongodb://127.0.0.1:27017/";
return mongo.connect(mongoUrl)
.then(async function(client) {
var s = "start";
var documents = await
client.db("dbName").collection("collectionName")
.find()
.toArray();
for (const doc of documents)
s += " | " + await doc.item;
return s + " end";
});
}
The issue was that I thought that since "getRoutes" was marked as "async", the stuff inside ".then" was async as well. But I really needed to mark "function(client)" as "async". I also needed to stop using "forEach" and use a more traditional iteration over the collection.
I had actually marked "function(client)" as "async" before, but it was out of blind trial and error, and so I never used "await" properly. I didn't really start to understand it until I read this blog by Anton Lavrenov.
Though I only asked the question recently, I was working on it before that for a long time. Really happy with where I'm at now. And of course thank you #desoares for pointing out my silly error in the version of code I was working with above.
As in asynchronous programming we used to callbacks and promises.
Here I am stuck in a problem that may be used to promises. I google it a lot but there is nothing found that solved my problem.
Here My code that I am doing to send push notification in android device.
router.post('/check-notifications', function(req, res, next) {
var user_id = req.body.user_id;
var response = {};
var gcm = require('push-notify').gcm({
apiKey: gcm_apiKey,
retries: 0
});
connection.query('select device_id from devices where user_id = '+ user_id, function (err, result) {
if ( result.length ) {
for (var i = 0; i < result.length; i++) {
console.log(i + 'before notify');
gcm.send({
registrationId: result[i]['device_id'],
data: result[0]
});
console.log(i + 'before transmitted');
gcm.on('transmitted', function (result, message, registrationId) {
console.log('transmitted');
});
gcm.on('transmissionError', function (error, message, registrationId) {
console.log(message);
});
console.log(i + 'after notify');
}
}
});
response['success'] = true;
response['msg'] = 'sent successfully';
res.json(response);
});
Output :
0before notify
0before transmitted
0after notify
1before notify
1before transmitted
1after notify
transmitted
transmitted
transmitted
transmitted
And I think It should be like this.
0before notify
0before transmitted
transmitted
0after notify
1before notify
1before transmitted
transmitted
1after notify
You can use async.mapSeries method for chaining notifications. Replace for loop to:
async.mapSeries(result, function(item, callback) {
gcm.send({
registrationId: item['device_id'],
data: data
});
gcm.on('transmitted', function(result, message, registrationId) {
console.log('transmitted');
callback(null, message, registrationId);
});
gcm.on('transmissionError', function(error, message, registrationId) {
callback(error, message, registrationId);
});
}, function (err, results) {
if (err) throw err;
response['success'] = true;
response['msg'] = 'sent successfully';
res.json(response);
})
I recommend using Bluebird JS for Promise flow-control.
var Promise = require('bluebird'); // Require bluebird, and call it 'Promise', the code below is version 3.x syntax
var connection = {'query': '???'}; // assuming `connection` is already defined somewhere else
var gcm_apiKey = '???'; // assuming `gcm_apiKey` is already defined
router.post('/check-notifications', function (req, res, next) {
var user_id = req.body.user_id;
var gcm = require('push-notify').gcm({
apiKey: gcm_apiKey,
retries: 0
});
// assuming `connection` is already defined somewhere else
// Make an async version of connection.query
connection.queryAsync = Promise.promisify(connection.query);
connection.queryAsync('select device_id from devices where user_id = ' + user_id)
// Bluebird's Promise.map would execute the following block once per result, asynchronously.
// The sequence of who runs first and who completes first is undefined
.map(function (result, i) {
// the `result` argument here is `result[i]` of the original code, since we're in the map context
// Here we have to create a promise to consume events
return new Promise(function (resolve, reject) {
console.log(i + 'before notify');
gcm.send({
registrationId: result['device_id'],
data: result // original code is written as result[0], which I don't quite understand. Always sending the first result?
});
// This does not make sense console logging here, as it is not actually 'before transmitted'
// It's just binding onto the event
// console.log(i + 'before transmitted');
gcm.on('transmitted', function (result, message, registrationId) {
// Check registrationId
if (registrationId === result['device_id']) {
console.log('transmitted');
resolve(result); // use 'result' as the Promise's resolved value
}
});
gcm.on('transmissionError', function (error, message, registrationId) {
// Check registrationId
if (registrationId === result['device_id']) {
console.log(message);
reject(message); // reject errors and send the message as the promise's reject reason
}
});
// Technically, you should log it as "after event binding"
console.log(i + 'after notify');
});
}).then(function (results) {
// `results` should contain all the result from the 'transmitted' event
var response = {};
response['success'] = true;
response['msg'] = 'sent successfully';
res.json(response);
});
});
Note: The is actually more or less doable without any libraries but with native Promises, but the syntax would be more cluttering.
I am trying to understand control flow in Node.js applications. Specifically does control returns to the original function once callback method completes (like a callback stack in recursive calls). I wrote a simple program that make a GET call and return the data. Here is the program:
Code:
var async = require('async');
var http = require('http');
function getGoogleData(url, callback) {
http.get(url, function(response) {
if (response.statusCode == 200) {
var googleInfo = '';
response.on('data', function(chunk) {
console.log("receiving data... ");
googleInfo += chunk;
return;
});
response.on('end', function() {
console.log("End of data receive... ");
response.setEncoding('utf8');
return callback(null, googleInfo);
});
}
console.log("I am here but why!");
//callback(new Error("GET called failed status_code=" + response.statusCode));
});
console.log("Return from get google data");
}
async.waterfall([
function(callback) {
console.log("In func 1");
getGoogleData("http://www.google.com", callback);
},
function(data, callback) {
console.log("In func 2");
callback(data);
}],
function (err, res) {
console.log("In err fn");
});
Here is output of the program:
Output:
In func 1
Return from get google data
I am here but why!
receiving data...
receiving data...
End of data receive...
In func 2
In err fn
Can someone help me understand why 'I am here but why!' line gets printed as the second output line in console log even after returning from 'data' event emitter? What is the overall control flow here?
The reason you're seeing that message logged first is that all that the code inside the if block is doing is adding event handlers. Those events are emitted some time in the future, after your console.log has already executed.
It's a similar reason why "Return from get google data" gets printed before the request finishes, because the http request is asynchronous.
I am using Javascript, webdriverio (v2.1.2) to perform some data extraction from an internal site. So the idea is
Authenticate
Open the required URL, when authenticated
In the new page, search for an anchor tag having specific keyword
Once found, click on the anchor tag
Below is what I have tried and it works (last two points). I had to use Q and async to achieve it. I was hoping to use only Q to achieve it. Can someone help me, on how to achieve it using Q only ??
var EmployeeAllocationDetails = (function () {
'use stricy';
/*jslint nomen: true */
var Q = require('Q'),
async = require('async'),
_ead_name = 'Employee Allocation Details',
goToEadFromHome;
goToEadFromHome = function (browserClient) {
browserClient.pause(500);
var deferred = Q.defer();
browserClient.elements('table.rmg td.workListTD div.tab2 div.contentDiv>a', function (err, results) {
if (err) {
deferred.reject(new Error('Unable to get EAD page. ' + JSON.stringify(err)));
} else {
async.each(results.value, function (oneResult, callback) {
console.log('Processing: ' + JSON.stringify(oneResult));
browserClient.elementIdText(oneResult.ELEMENT, function (err, result) {
if (err) {
if (err.message.indexOf('referenced element is no longer attached to the DOM') > -1 ){
callback();
} else {
callback('Error while processing :' + JSON.stringify(oneResult) + '. ' + err);
}
} else if(!result){
console.log('result undefined. Cannot process: ' + JSON.stringify(oneResult));
callback();
} else if(result.value.trim() === _ead_name){
deferred.resolve(oneResult);
callback();
}
});
}, function (err) {
// if any of the processing produced an error, err would equal that error
if( err ) {
// One of the iterations produced an error.
// All processing will now stop.
console.log('A processing failed to process. ' + err);
} else {
console.log('All results have been processed successfully');
}
}); //end of async.each
}
});
return deferred.promise;
};
return {
launchEad : goToEadFromHome
}
})();
module.exports = EmployeeAllocationDetails;
Related Github Issue link https://github.com/webdriverio/webdriverio/issues/123
I think you should use async. I think your code is great. It runs everything in parallel and it handles error well.
If
If you want to remove async, there are several options:
use Q flow control
copy paste async's implementation
implement it yourself
If you try to use Q's flow control it will look something like this (pseudo-code):
var getTextActions = [];
function createAction(element){
return function(){
return element.getText();
}
}
each(elements, function(element){ getTextActions.push( createAction(element) ) });
Q.all(getTextActions).then(function(results) {
... iterate all results and resolve promise with first matching element..
} );
note this implementation has worse performance. It will first get the text from all elements, and only then try to resolve your promise. You implementation is better as it all runs in parallel.
I don't recommend implementing it yourself, but if you still want to, it will look something like this (pseudo-code):
var elementsCount = elements.length;
elements.each(function(element){
element.getText(function(err, result){
elementsCount --;
if ( !!err ) { logger.error(err); /** async handles this much better **/ }
if ( isThisTheElement(result) ) { deferred.resolve(result); }
if ( elementsCount == 0 ){ // in case we ran through all elements and didn't find any
deferred.resolve(null); // since deferred is resolved only once, calling this again if we found the item will have no effect
}
})
})
if something is unclear, or if I didn't hit the spot, let me know and I will improve the answer.
I'm trying to use promises with nodejs (I'm trying with node-promise package); however, without any success. See the code below:
var express = require('express'),
request = require('request'),
promise = require('node-promise');
app.get('/promise', function(req, res) {
var length = -1;
new promise.Promise(request(
{uri: "http://www.bing.com"},
function (error, response, body) {
if (error && response.statusCode !== 200) {
console.log("An error occurred when connected to the web site");
return;
}
console.log("I'll return: " + body.length);
length = body.length;
}
)).then(function(result) {
console.log("This is what I got: " + length);
console.log("Done!");
});
res.end();
});
The output of the above code is I'll return: 35857 only and it doesn't go to the then part.
I change the code then to be:
app.get('/promise', function(req, res) {
var length = -1;
promise.when(
request(
{uri: "http://www.bing.com"},
function (error, response, body) {
if (error && response.statusCode !== 200) {
console.log("An error occurred when connected to the web site");
return;
}
console.log("I'll return: " + body.length);
length = body.length;
}
),
function(result) {
console.log("This is what I got: " + length);
console.log("Done!");
},
function(error) {
console.log(error);
}
);
res.end();
});
This time the output is This is what I got: -1 then Done!... looks like the "promise" was not called this time.
So:
What's needed to be done to fix the code above? Obviously I'm not doing it right :)
Is node-promise "the way to go" when I'm doing promises, or is there a better way/package? i.e. simpler and more production-ready.
Thanks.
Try jquery-deferred-for-node.
I'm not an expert but understand that this lib tends to be favoured by programmers who work both server-side and client-side.
Even if you don't already know jQuery's Deferreds, the advantages of going this route are that :
the documentation is excellent (it comprises links to the jQuery docs), though you may struggle to find examples specific to Node.
methods are chainable.
jQuery Callbacks are also included.
when one day you need to do asynchronous stuff client-side, then there's virtually nothing to relearn - the concepts are identical and the syntax very nearly so. See the "Correspondances" section in the github page hyperlinked above.
EDIT
I'm not a node.js person so I'm guessing here but based on your code above, you might want to consider something along the following lines with jquery-deferred-for-node :
var express = require('express'),
request = require('request'),
Deferred = require('JQDeferred');
function fetch(uri, goodCodes) {
goodCodes = (!goodCodes) ? [200] : goodCodes;
var dfrd = Deferred(); // A Deferred to be resolved/rejected in response to the `request()`.
request(uri, function(error, response, body) {
if (!error) {
var isGood = false;
// Loop to test response.statusCode against `goodCodes`.
for (var i = 0; i < goodCodes.length; i++) {
if (response.statusCode == goodCodes[i]) {
isGood = true;
break;
}
}
if (isGood) {
dfrd.resolve(response.statusCode, body);
} else {
dfrd.reject(response.statusCode, "An invalid response was received from " + uri);
}
} else {
dfrd.reject(response.statusCode, "An error occurred attempting to connect to " + uri);
}
});
// Make promise derived from dfrd available to "consumer".
return dfrd.promise();
};
//...
app.get('/promise', function(req, resp) {
fetch("http://www.bing.com").done(function(statusCode, result) {
console.log("Done! This is what I got: " + result.length);
}).fail(function(statusCode, message) {
console.log("Error (" + statusCode + "): " + message);
});
resp.end();
};
Here, I have tried to write a generalized utility for fetching a resource in such a way that the asynchronous response (or error) can be handled externally. I think this is broadly along the lines of what you were trying to achieve.
Out of interest, where do console.log() messages end up with node.js?
EDIT 2
Above, I have given Deferred an initial capital, as is conventional for Constructors
With jQuery Deferreds, there must be any number of ways to fetch() consecutively. The approach below leaves fetch() as it was, and introduces fetch_() to act as its front-end. There may be simpler ways but this allows fetch() to remain a general utility, functionally equivalent to the client-side jQuery.ajax().
function fetch_(uri){
return function(){
return fetch(uri, [200]).then(function(statusCode, result){
console.log("Done! This is what I got: " + result.length);
},function(statusCode, message){
console.log("Error (" + statusCode + "): " + message);
});
};
}
Note that function fetch() returns a function. It has to be like this because where fetch() is called, we want an unexecuted function, not (yet) the result of that function.
Now let's assume an array of uris is available. This can be hard-coded or built dynamically - whatever the application demands.
var uris = [
'http://xxx.example.com',
'http://yyy.example.com',
'http://zzz.example.com'
];
And now, a variety of ways in which fetch_() might be called :
//v1. To call `resp.end()` when the fetching process starts.
app.get('/promise', function(req, resp) {
fetch_(uris[0])().then(fetch_(uris[1])).then(fetch_(uris[2]));
resp.end();
});
//v2. To call `resp.end()` when the fetching process has finished.
app.get('/promise', function(req, resp){
fetch_(uris[0])().then(fetch_(uris[1])).then(fetch_(uris[2])).always(resp.end);
});
//v3. As v2 but building a `.then()` chain of any (unknown) length.
app.get('/promise', function(req, resp){
var dfrd = Deferred().resolve();//
$.each(uris, function(i, uri){
dfrd = dfrd.then(fetch_(uri));
});
dfrd = dfrd.always(resp.end);
});
untested
I have more confidence in v1 and v2. v3 may work.
v2 and v3 should both give exactly the same behaviour but v3 is generalized for any number of uris.
Everything may need debugging.
I would recommend using Q: https://github.com/kriskowal/q. I believe that it's used internally by other frameworks (like jQuery deferred implementation).
I believe that the documentation is "fine"; the syntax is consistent with other promise implementations... and it has a node adapter.
So your deferred style approach:
var deferred = Q.defer();
FS.readFile("foo.txt", "utf-8", function (err, res) {
if (!err) {
deferred.resolve(res);
} else {
deferred.reject(err);
}
});
return deferred.promise;
Can be written more concisely as:
var deferred = Q.defer();
FS.readFile("foo.txt", "utf-8", deferred.makeNodeResolver());
return deferred.promise;