I'm using this framework to make screenshots of several urls. The process of taking the screenshot is async, and the method does not provide a way to execute a callback, and I want to execute a callback when each screenshot is made on this script:
nightmare = new Nightmare();
urls.forEach(function (url) {
nightmare.goto(url).screenshot(path);
});
nightmare.run(function () {
console.log('finished all');
});
Any ideas how can I do this?
I found a way to do this, with the "use" method for executing plugins.
nightmare = new Nightmare();
urls.forEach(function (url) {
nightmare.goto(url).screenshot(path).use(function () {
console.log('finished one');
});
});
nightmare.run(function () {
console.log('finished all');
});
This appears to be the purpose of the run() method. You probably want to set up and run each screenshot within the loop, since the screenshot() method relies on the phandomjs method render(), and render() is strictly synchronous (at least as of a year ago):
urls.forEach(function (url) {
nightmare = new Nightmare();
nightmare.goto(url).screenshot(path).run(function(err, nightmare) {
console.log('this executes when your screenshot completes');
// run() appropriately tears down the nightmare instance
});
});
console.log('finished all');
You don't gain any asynchronous benefits from setting up all the screenshots at once, and "finished all" is guaranteed to only run once all screenshots have been rendered.
Alternatively, in the nightmarejs source, it looks like screenshot() does take a second done parameter that appears to be a callback, but it passes it directly into the phantomjs render() method, and as seen in the above link there was some resistance to allowing that method to take a callback.
Related
I am working on setting up an automation test suite for an application using selenium and jest and it turns out that the console never reaches the inner body of the minimalist test case written below.
describe('When a user Opens Launchpad', () => {
test('It should be able to Navigate to Tasks Application without errors', async () => {
driver.get('http://localhost:4004/fiori.html').then(function () {
const temp = driver.findElement(By.xpath("li[#id='__tile11']"));
temp.then(function (element){
element.getAttribute("innerHTML");
expect(element.getText()).toBe("VT Dashboard");
})
});
}, 200000);
});
I looked online and tried multiple fixes like putting the driver.get() method above all these functions, making the test cases synchronous and using getText() instead of getAttribute() but none of them worked.
I either get an element not found error (The element actually exists when I check it on the chromium browser) or the test case executes successfully without reaching the expect statement in debug mode.
Bottomline is that driver.findElement() returns a promise instead of an element and would be great if I could get an element instead of promise.
Any help or correction here would be greatly appreciated.
If the function is async you should return the promise chain from that function or just use await keyword. So try following:
test('It should be able to Navigate to Tasks Application without errors', async () => {
await driver.get('http://localhost:4004/fiori.html');
const temp = await driver.findElement(By.xpath("li[#id='__tile11']"));
element.getAttribute("innerHTML");
expect(element.getText()).toBe("VT Dashboard");
}, 200000);
or
test('It should be able to Navigate to Tasks Application without errors', async () => {
return driver.get('http://localhost:4004/fiori.html').then(function () {
const temp = driver.findElement(By.xpath("li[#id='__tile11']"));
temp.then(function (element){
element.getAttribute("innerHTML");
expect(element.getText()).toBe("VT Dashboard");
})
});
}, 200000);
I am working with MySQL server, building a NodeJS server.
SomeWhere in the code I have async code that is not waiting, I believe its has something to do with the forEach function.
Is there anything wrong with my implementation of my next function:
async addResponsesToTasks(input, response, isFromCache) {
if (!isFromCache) {
this.saveResponseToCache(input, response);
}
console.log("===7===");
await response.forEach(async (pokemon) => {
console.log("===8===", pokemon);
await this.addTaskToFile(pokemon, false);
console.log("===13===");
});
return true;
}
And this is the output shows that it is not waiting for creation and save in the DB to finish, and jump to do some other things:
Prints of the output - can see 10,12,13,14,15 and only then 11
Hope you could maybe spot what I am missing.
Thanks in advance!
What's happening here is more of a JavaScript thing than a Sequelize thing.
The await is being applied to the lines of code that follow Item.create() inside of this function, but outer functions are continuing to execute.
console.log('9')
saveTaskToDb(task)
console.log('12')
In this code, '12' is going to get logged out before your '11', because this outer code is going to continue to execute, even if the code in saveTaskToDb is awaiting the resolution of the create() method.
To solve this, you'll either need to move all of your asynchronous code into the same code block, or you'll need to return your own promise in the saveTaskToDb function, and await saveTaskToDb.
So Solution was not using forEach, rather using for of loop like that:
async addResponsesToTasks(input, response, isFromCache) {
if (!isFromCache) {
this.saveResponseToCache(input, response);
}
for (const pokemon of response) {
await this.addTaskToFile(pokemon, false);
}
return true;
}
Based on this question: Using async/await with a forEach loop
I am new to nodejs/expressjs and mongodb. I am trying to create an API that exposes data to my mobile app that I am trying to build using Ionic framework.
I have a route setup like this
router.get('/api/jobs', (req, res) => {
JobModel.getAllJobsAsync().then((jobs) => res.json(jobs)); //IS THIS THe CORRECT WAY?
});
I have a function in my model that reads data from Mongodb. I am using the Bluebird promise library to convert my model functions to return promises.
const JobModel = Promise.promisifyAll(require('../models/Job'));
My function in the model
static getAllJobs(cb) {
MongoClient.connectAsync(utils.getConnectionString()).then((db) => {
const jobs = db.collection('jobs');
jobs.find().toArray((err, jobs) => {
if(err) {
return cb(err);
}
return cb(null, jobs);
});
});
}
The promisifyAll(myModule) converts this function to return a promise.
What I am not sure is,
If this is the correct approach for returning data to the route callback function from my model?
Is this efficient?
Using promisifyAll is slow? Since it loops through all functions in the module and creates a copy of the function with Async as suffix that now returns a promise. When does it actually run? This is a more generic question related to node require statements. See next point.
When do all require statements run? When I start the nodejs server? Or when I make a call to the api?
Your basic structure is more-or-less correct, although your use of Promise.promisifyAll seems awkward to me. The basic issue for me (and it's not really a problem - your code looks like it will work) is that you're mixing and matching promise-based and callback-based asynchronous code. Which, as I said, should still work, but I would prefer to stick to one as much as possible.
If your model class is your code (and not some library written by someone else), you could easily rewrite it to use promises directly, instead of writing it for callbacks and then using Promise.promisifyAll to wrap it.
Here's how I would approach the getAllJobs method:
static getAllJobs() {
// connect to the Mongo server
return MongoClient.connectAsync(utils.getConnectionString())
// ...then do something with the collection
.then((db) => {
// get the collection of jobs
const jobs = db.collection('jobs');
// I'm not that familiar with Mongo - I'm going to assume that
// the call to `jobs.find().toArray()` is asynchronous and only
// available in the "callback flavored" form.
// returning a new Promise here (in the `then` block) allows you
// to add the results of the asynchronous call to the chain of
// `then` handlers. The promise will be resolved (or rejected)
// when the results of the `job().find().toArray()` method are
// known
return new Promise((resolve, reject) => {
jobs.find().toArray((err, jobs) => {
if(err) {
reject(err);
}
resolve(jobs);
});
});
});
}
This version of getAllJobs returns a promise which you can chain then and catch handlers to. For example:
JobModel.getAllJobs()
.then((jobs) => {
// this is the object passed into the `resolve` call in the callback
// above. Do something interesting with it, like
res.json(jobs);
})
.catch((err) => {
// this is the error passed into the call to `reject` above
});
Admittedly, this is very similar to the code you have above. The only difference is that I dispensed with the use of Promise.promisifyAll - if you're writing the code yourself & you want to use promises, then do it yourself.
One important note: it's a good idea to include a catch handler. If you don't, your error will be swallowed up and disappear, and you'll be left wondering why your code is not working. Even if you don't think you'll need it, just write a catch handler that dumps it to console.log. You'll be glad you did!
In my Cordova project, I have a hook which does RequireJS optimization (r.js) on after_prepare. That optimization is inherently asynchronous, so my hook code returns before all optimization is fully finished.
For example, this causes issues when running cordova run browser: On the first page load, optimization has not finished yet and the site looks broken.
Is there a way to make the Cordovoa build process to block until a certain hook fires a callback? Or can the optimizer be run in a blocking/sync way?
An alternative I could think of is using a different process for optimization and busy-wait in the main for it to finish, but that looks like an overkill and bad practice to me.
You can use the built-in promise module to block Cordova from proceeding until the hook has resolved.
Something along these lines:
#!/usr/bin/env node
var deferral;
function doSomethingAsync(){
somethingAync
.success(function(){
deferral.resolve();
})
.fail(function(err){
deferral.reject(err);
});
}
module.exports = function(ctx) {
deferral = ctx.requireCordovaModule('q').defer();
doSomethingAsync();
return deferral.promise;
};
You don't need to call context, you can simply return a Promise from within the module.exports function
module.exports = context => {
return new Promise(resolve => {
setTimeout(() => resolve(), 1000);
});
};
I tested and it works. The problem arises because in Cordova versions => 9 you cannot use context.requireCordovaModule('q')
If you don't want to use Promise, just do
module.exports = context => {
var deferral = require('q').defer();
doSomethingAsync(() => {
deferral.resolve();
});
return deferral.promise;
};
I've got a NodeJS app i'm building (using Sails, but i guess that's irrelevant).
In my action, i have a number of requests to other services, datasources etc that i need to load up. However, because of the huge dependency on callbacks, my code is still executing long after the action has returned the HTML.
I must be missing something silly (or not quite getting the whole async thing) but how on earth do i stop my action from finishing until i have all my data ready to render the view?!
Cheers
I'd recommend getting very intimate with the async library
The docs are pretty good with that link above, but it basically boils down to a bunch of very handy calls like:
async.parallel([
function(){ ... },
function(){ ... }
], callback);
async.series([
function(){ ... },
function(){ ... }
]);
Node is inherently async, you need to learn to love it.
It's hard to tell exactly what the problem is but here is a guess. Assuming you have only one external call your code should look like this:
exports.myController = function(req, res) {
longExternalCallOne(someparams, function(result) {
// you must render your view inside the callback
res.render('someview', {data: result});
});
// do not render here as you don't have the result yet.
}
If you have more than two external calls your code will looks like this:
exports.myController = function(req, res) {
longExternalCallOne(someparams, function(result1) {
longExternalCallTwo(someparams, function(result2) {
// you must render your view inside the most inner callback
data = {some combination of result1 and result2};
res.render('someview', {data: data });
});
// do not render here since you don't have result2 yet
});
// do not render here either as you don't have neither result1 nor result2 yet.
}
As you can see, once you have more than one long running async call things start to get tricky. The code above is just for illustration purposes. If your second callback depends on the first one then you need something like it, but if longExternalCallOne and longExternalTwo are independent of each other you should be using a library like async to help parallelize the requests https://github.com/caolan/async
You cannot stop your code. All you can do is check in all callbacks if everything is completed. If yes, go on with your code. If no, wait for the next callback and check again.
You should not stop your code, but rather render your view in your other resources callback, so you wait for your resource to be reached before rendering. That's the common pattern in node.js.
If you have to wait for several callbacks to be called, you can check manually each time one is called if the others have been called too (with simple bool for example), and call your render function if yes. Or you can use async or other cool libraries which will make the task easier. Promises (with the bluebird library) could be an option too.
I am guessing here, since there is no code example, but you might be running into something like this:
// let's say you have a function, you pass it an argument and callback
function myFunction(arg, callback) {
// now you do something asynchronous with the argument
doSomethingAsyncWithArg(arg, function() {
// now you've got your arg formatted or whatever, render result
res.render('someView', {arg: arg});
// now do the callback
callback();
// but you also have stuff here!
doSomethingElse();
});
});
So, after you render, your code keeps running. How to prevent it? return from there.
return callback();
Now your inner function will stop processing after it calls callback.