Reputation: 4686
Here's my Gruntfile and the output.
As you can see in the output, there are a couple of issues related to asynchronous tasks:
imagemin
is called and the next one comes straight ahead. This makes its output appear in the end of the tasks, what's quite messy;build
, which is a custom task, is using var done = this.async()
and calling done()
after finishing the command; however, this only works correctly if I run the task alone; running it with another tasks makes it run async too;build
running later, jasmine
has nothing to test and thus is useless.Is there a way to fix this behavior?
Upvotes: 11
Views: 10099
Reputation: 5916
As you could read in the Grunt documentation:
If a task is asynchronous, this.async method must be invoked to instruct Grunt to wait. It returns a handle to a "done" function that should be called when the task has completed.
And a short example would be similar to:
// Tell Grunt this task is asynchronous.
var done = this.async();
// Your async code.
fetchData(url).then( data => {
console.log(data);
done();
}).catch( error => {
console.err(error);
done(false); // false instructs Grunt that the task has failed
});
Upvotes: 0
Reputation: 12441
I believe your problem is with this task:
grunt.registerTask('prepare-dist', 'Creates folders needed for distribution', function() {
var folders = ['dist/css/images', 'dist/imgs/icons'];
for (var i in folders) {
var done = this.async();
grunt.util.spawn({ cmd: 'mkdir', args: ['-p', folders[i]] }, function(e, result) {
grunt.log.writeln('Folder created');
done();
});
}
});
If you have multiple folders, both async() and done() will be called multiple times. Async is implemented as a simple flag (true/false) and is meant to be called once. The first done() call allows any follow on tasks to run.
There are many ways to move the calls to async and done out of the loop. A quick google search on something like: nodejs how to callback when a series of async tasks are complete
will give you some additional options. A couple of quick (& dirty) examples:
// Using a stack
(function() {
var work = ['1','2','3','4','5']
function loop(job) {
// Do some work here
setTimeout(function() {
console.log("work done");
work.length ? loop(work.shift()) : done();
}, 500);
}
loop(work.shift());
function done() {
console.log('all done');
}
})();
-- or --
// Using a counter (in an object reference)
(function() {
var counter = { num: 5 }
function loop() {
// Do some work here
setTimeout(function() {
--counter.num;
console.log("work done");
counter.num ? loop() : done();
}, 500);
}
loop();
function done() {
console.log('all done');
}
})();
Upvotes: 9