I'm trying to run callbacks in specific order.
Basically I have a gulp task that receives an array with four CSS paths. I need minify each file and print status about progress. Something like that:
Minifying file AAA.css: OK
Minifying file BBB.css: OK
Minifying file CCC.css: FAIL
Minifying file DDD.css: OK
First I write Minifying file AAA.css, so I run some gulp methods, and on("end") or on("error") it should complete the phrase with OK\n or FAIL\n, respectively.
My problem is that it is printing somethink like:
Minifying file AAA.css: Minifying file BBB.css: {...} DDD.css: Finished {...}.
OK
OK
FAIL
OK
This is how I trying to do:
gulp.task("watch", function () {
var files = [ "AAA.css", "BBB.css", "CCC.css", "DDD.css" ];
var promise = Q();
underscore.each(files, function (file) {
minify(promise, file);
});
return promise;
});
function minify(promise, file) {
promise.then(function() { write("Minifying " + file + ": ") });
promise.then(function() {
return gulp.src(file).{...}
.on("error", function() { write("FAIL"); })
.on("end", function() { write("OK"); })
});
}
I tried use Q.defer() and create a promise for each file in loop too, but without success... Like:
function minify(file) {
var promise = Q();
promise.then(function() { write("Minifying " + file + ": ") });
promise.then(function() {
return gulp.src(file).{...}
.on("error", function() { write("FAIL"); })
.on("end", function() { write("OK"); })
});
return promise();
}
What should I do? Maybe Promise or Deferred will not solve my problem?
Edit: my current code is http://pastebin.com/tSaXH1iF
The problem is the usual async problem: gulp.src() will finish long after you've printed your "Minifying...". The solution is to wait for it to finish before printing the "Minifying..." message:
function minify(file) {
var promise = Q();
promise.then(function() {
return gulp.src(file).{...}
.on("error", function() { write("Minifying " + file + ":FAIL"); })
.on("end", function() { write("Minifying " + file + ":OK"); })
});
return promise();
}
There's really no simple way around it unless you want to use some fancy terminal trickery to move the cursor to the correct line to print "OK" or "FAIL".
building on slebetman's answer, I do not think you are building promises properly( unless gulp.src returns promise), Your code would work but with current state the promise has no effect.
with Q.defer you can promisify the pipe like:
function minify(file) {
var deferred = Q.defer();
gulp.src(file).{...}
.on("error", function(err) { write("Minifying " + file + ": FAIL"); deferred.reject(err);})
.on("end", function() { write("Minifying " + file + ": OK");deferred.resolve(); });
return promise();
}
I finally found the mistake. Basically, .then() will expect a "promise factory", instead of "promise instance".
I was incorrectly running the function minifyCSS(), instead of bind it to .then().
Minify CSS function: it was correct. I created a defer on it and return it promise.
var deferred = Q.defer();
gulp.src(...)
.pipe(...)
.on("end", ... deffered.resolve() ...);
return deferred.promise;
Before:
var promise = Q();
promise.then( ... start message ... );
promise.then(minifyCSS(file));
return promise;
After:
var promise = Q();
promise.then( ... start message ... );
promise.then(minifyCSS.bind(null, file));
return promise;
Note only the second .then() call on each example.
A small logical mistake. Gulp was executed instantly when I called minifyCSS() on first example (before), instead of execute after last .then() finished (like in after).
Related
How can i run this if statements synchronously. I have been trying many times but unable to fixed this. (I am nodejs beginner).
i am trying to use async/await here but it is not work.
how can i check first if condition is completed and then second if statement will run!
Please help.
here is my dummy codes:
record1='10';
record2='20';
function main(){
if(record1){
console.log('-------------------------');
console.log('I am record 1')
val='John',
firstJob(val)
}
if(record2){
console.log('I am record 2')
val='Rahul',
firstJob(val)
}
}
async function firstJob(val){
console.log('Hello, I am ' + val)
await secondJob(val);
}
async function secondJob(val){
console.log(val+ ' is a nodeJs beginner!')
await listFiles()
}
function thirdJob(arg){
if (arg='pass'){
console.log('This is end of the one if condition')
}
}
function listFiles (){
return new Promise((resolve, reject) => {
setTimeout(() => {
const path = require('path');
const fs = require('fs');
const { exit } = require('process');
const directoryPath = path.join(__dirname, '../');
console.log('List of Avaialble Files :');
fs.readdir(directoryPath, { withFileTypes: true },function (err, files) {
if (err) {
return console.log('Unable to scan directory: ' + err);
}
files.forEach(function (file) {
if (file.isFile()){
console.log(file);
}
});
});
arg='pass'
thirdJob();
}, 2000)
})
}
main();
The short answer is you can't "make them run synchronously".
You have to patiently wait until they're done to get the answer.
So, without making main async, you have to use the promises the old fashioned way, and sequence the actions using then.
record1='10';
record2='20';
function main(){
Promise.resolve()
.then(() => {
if(record1){
console.log('-------------------------');
console.log('I am record 1');
val='John';
return firstJob(val)
}
})
.then(() => {
if(record2){
console.log('I am record 2')
val='Rahul';
return firstJob(val)
}
});
}
async function firstJob(val){
console.log('Hello, I am ' + val)
await secondJob(val);
}
async function secondJob(val){
console.log(val+ ' is a nodeJs beginner!')
await listFiles()
}
main();
I've just included the snippet for the if and promise stuff. The gist here is that you conditionally chain together your calls to firstJob.
Each call to then allows you to (potentially, it's not required) attach another promise to the execution of the one that just finished. In the snippet above, we're doing that only if the condition is truthy by returning the promise from the calls to firstJob.
By the way, your implementation of listFiles isn't ever going to finish because you never invoke resolve to the promise you made inside the function. This solves the problem by resolving your promise once the looping is done.
function listFiles (){
return new Promise((resolve, reject) => {
setTimeout(() => {
const path = require('path');
const fs = require('fs');
const { exit } = require('process');
const directoryPath = path.join(__dirname, '../');
console.log('List of Avaialble Files :');
fs.readdir(directoryPath, { withFileTypes: true },function (err, files) {
if (err) {
console.log('Unable to scan directory: ' + err);
reject(err);
}
files.forEach(function (file) {
if (file.isFile()){
console.log(file);
}
});
resolve();
});
arg='pass'
thirdJob();
}, 2000)
})
}
Note the added call to resolve once you've completed your loop.
I also added a call to reject in the case that readdir returned an error, since that is the proper way to propagate it with your manual promise.
A few more pointers, generally modules are required once at the top of the file, instead of dynamically inside of a function. The penalty for doing it that way you have is not bad, there is a cache for required modules. It's just not idiomatic.
if (arg='pass'){
Doesn't do any equality check, that's an assignment, you need ==, or === if you want to check for equality.
A() function return promises after 1000 ms and throws an error. So, the next execution should be into catch. But, .then() function gets executed even after the main function throws an error.
Test.js
var Test1 = require("./Test1.js")
var Q = require('q');
var value = "Hardik";
var value1 = "Shah";
A()
.then(Test1.B(value, value1))
.catch(function(e){
console.log("In catch: ", e.message);
});
function A(){
console.log("In A function");
return Q.nfcall(AInner);
}
function AInner(callback){
setTimeout(function() {
callback({message: "Error from A Inner"});
}, 1000)
}
Test1.js
'use strict';
var Q = require("q");
module.exports = {B:B}
function B(value, value1){
console.log("In B function: ", value, " ", value1);
return Q.nfcall(BInner);
}
function BInner(callback){
console.log("In BInner function");
callback({message: "Error from BInner"});
}
Actual Output:
In A function
In B function: Hardik Shah
In BInner function
In catch: Error from A Inner
Expected Output:
In A function
Error from A Inner // After 1000 ms
I have solved issue by modifying below code: Works perfect
A()
.then(function(){
return Test1.B(value, value1)
}).then(function(data){
console.log("final data", data);
})
.catch(function(e){
console.log(e.message);
});
But, what is wrong with the above code?
Please give me a good explanation with the correct way to write code in the sequence of then rather than under then.
You can try here https://repl.it/#hrdk108/Hardik-Shah-Issue1 to reproduce an issue.
Issue is, you are invoking Test1.B(value, value1) inside then, rather than keeping it as callback. Because, once you used it as invocation, it started it's own promise chain. To fix it, change it to:
var Test1 = require("./Test1.js")
var Q = require('q');
var value = "Hardik";
var value1 = "Shah";
A()
.then(function() { Test1.B(value, value1) }) // note here
.catch(function(e){
console.log("In catch: ", e.message);
});
function A(){
console.log("In A function");
return Q.nfcall(AInner);
}
function AInner(callback){
setTimeout(function() {
callback({message: "Error from A Inner"});
}, 1000)
}
After a long brainstorm, I have figured out and it is just a silly mistake.
That Mistake is just because I invoked Test1.B() while defining
into then. Which is already answered in the above answer. So, One solution is I have already mentioned in the question.
Second solution:
The correct way to write a then sequence is:
Test1.B function without arguments:
A()
.then(Test1.B)
.catch(function(e){
console.log("In catch: ", e.message);
});
Test1.B with arguments: use bind
A()
.then(Test1.B.bind(null, value, value1))
.catch(function(e){
console.log("In catch: ", e.message);
});
Check here corrected example https://repl.it/#hrdk108/Hardik-Shah-Issue1
For Just FYI,
Actually, When you are using Q.nfcall you should take care of passing arguments design.
nfcall expects arguments provided individually
For Example:
Q.nfcall(B, value, value1);
Using child process I execute a Python script does something a spits data back. I used a Node promise to wait until I get the Python data.
The problem I am facing is there is a callback for an anonymous function, the callback takes two parameters one of which is the python data. Code below explains. How do I call the promise, wait until it resolves then call the callback.
Node Promise
var spawn = require("child_process").spawn;
function sensorData()
{
return new Promise(function(resolve, reject)
{
var pythonProcess = spawn ("python",[pythonV1.py"]);
pythonProcess.stdout.on("data", function(data)
{
resolve(data);
});
});
}
Anonymous Function
...
onReadRequest : function(offest, callback)
{
#============DOES NOT WORK=========================
sensorData()
.then(function(data)
{
callback(this.RESULT_SUCCESS, data);
})
#===================================================
#call promise, wait and then call callback passing the python data
callback(this.RESULT_SUCCESS, new Buffer(#python data)
}
...
Many thanks
Unless you know that your pythonProcess will only return one line of data, it's bad practice to call resolve() on every stdout data call. It would be much better to collect data until the process closes, and return it all at once.
I'm also not used to dealing with buffers, so I'm casting stuff to strings here...
var spawn = require("child_process").spawn;
function sensorData()
{
return new Promise(function(resolve, reject)
{
var output = '';
var pythonProcess = spawn ("python",[pythonV1.py"]);
pythonProcess.stdout.on("data", function(data)
{
output += data.toString();
});
// Not sure if all of these are necessary
pythonProcess.on('disconnect', function()
{
resolve(output);
});
pythonProcess.on('close', function(code, signal)
{
resolve(output);
});
pythonProcess.on('exit', function(code, signal)
{
resolve(output);
});
});
}
...
onReadRequest : function(offest, callback)
{
#call promise, wait and then call callback passing the python data
sensorData()
.then(function(data)
{
callback(this.RESULT_SUCCESS, data);
})
.catch(function(err)
{
// Do something, presumably like:
callback(this.RESULT_FAILURE, err);
});
}
...
I'm using Promises for the first time, so please bear with me.
Basically, I'm not seeing the function in my .then() statement being called.
When I call t.t(), is it working correctly.
When I call t.tAsync(), t() is again called.
However the result isn't being passed into the then when I call t.tAync().then(console.log);
Here is my node module:
'use strict';
var t = function(){
console.log('inside t()');
return 'j';
};
module.exports = {
t: t
};
And here is my demo script:
'use strict';
require('should');
var Promise = require('bluebird');
var t = require('../src/t');
Promise.promisifyAll(t);
/*
Call t() once to demonstrate.
Call tAsync() and see t() is called
Call tAsync.then(fn), and then isn't called
*/
// this works as expected, calling t()
console.log('calling t()...' + t.t());
// this also works, calling t()
t.tAsync();
// the then() statement isn't called
t.tAsync().then(function(res){
// I expect this to be called
console.log('HHHUUUZZZAAAHHH' + res);
});
/*
Keep the script running 5 seconds
*/
(function (i) {
setTimeout(function () {
console.log('finished program');
}, i * 1000)
})(5);
And here is the output from the test:
inside t()
calling t()...j
inside t()
inside t()
finished program
Your then clause will never be called because the tAsync is expecting t to call the callback not return a value.
promisifyAll wraps Node.JS aysynchronous API's so the function it is wrapping needs to conform to the Node.JS callback signature:
function t(callback) {
callback(null, 'j');
}
However, I suspect based on your code that you do not want promiseifyAll but instead try() or method():
function t() {
return 'j';
}
Promise.try(t).then(function(result) {
console.log(result);
});
OR
var t = Promise.method(function() {
return 'j';
});
t().then(function(result) {
console.log(result);
});
For contrast the above is Bluebird.js specific. To perform this with generic Promises you would approach it one of two ways:
Using the Promise constructor:
function t() {
return new Promise(function(resolve, reject) {
resolve('j');
});
}
t().then(function(result) {
console.log(result);
});
Or, use the then chaining feature:
function t() {
return 'j';
}
Promise.resolve()
.then(t)
.then(function(result) {
console.log(result);
});
I was also not able to understand how "then" works. Below code example (just created to understand the flow) may help you:
var Promise = require('bluebird');
function task1(callback) {
setTimeout(function(){
console.log("taks1");
callback(null, "taks1");
}, 2000);
}
var taks1Async = Promise.promisify(task1);
taks1Async().then(function(result) {
console.log("Current task2, previous: " + result);
return "task2";
})
.then(function(result) {
console.log("Current task3, previous: " + result);
return "task3";
})
.catch(function(e) {
console.log("error: " + e);
});
console.log("Finished");
How can I avoid using a recursion like structure when I got several streams to open and I have to get an absolute end event to finish the logic.
var someArray = ['file1', 'file2', 'file3'];
someArray.forEach(function( file ) {
fs
.createReadStream( file )
.pipe( /* do some stuff */ )
.on('data', function( usageInfo ) {
// done?
});
}
I got several files I have to pipe through tp some processes. How can I setup an event that tells me when all of them are done?
Currently what I'm getting is each end event individually.
I can absolutely start each stream at the same time. I just need to somehow collect the end?
I could invoke a function call for each end event and count it... that sounds hacky though?...
I feel like there is a way to do this with promises but I don't know how.
I feel like there is a way to do this with promises but I don't know how.
Yes, there is. As promises do represent asynchronous values, you'd get a promise for the end of one stream:
var p = new Promise(function(resolve, reject) {
fs.createReadStream(file)
.on('error', reject)
.pipe(/* do some stuff */)
.on('end', resolve)
.on('error', reject); // call reject(err) when something goes wrong
});
It could be used like p.then(functio(usageInfo) { console.log("stream ended"); }).
Now if you create multiple promises, one for filename in your array, all the streams will run in parallel and resolve their respective promise when done. You then can use Promise.all to collect - read "await" - all the results from each of them into a new promise for an array of results.
var promises = ['file1', 'file2', 'file3'].map(function(file) {
return new Promise(function(resolve, reject) {
…
});
});
Promise.all(promises).then(function(usageInfos) {
console.log("all of them done", usageInfos),
}, function(err) {
console.error("(At least) one of them failed", err);
});
Use a counter:
var someArray = ['file1', 'file2', 'file3'];
var still_processing = someArray.length;
someArray.forEach(function( file ) {
fs.createReadStream( file )
.pipe( /* do some stuff */ )
.on('end', function() {
still_processing--;
if (!still_processing) {
// done
}
});
}
This is the basic mechanism. This control flow pattern is encapsulated by the async.parallel() function in async.js:
var someArray = ['file1', 'file2', 'file3'];
var streams_to_process = [];
someArray.forEach(function( file ) {
streams_to_process.push(function(callback) {
var result = "";
fs.createReadStream( file )
.pipe( /* do some stuff */ )
.on('end', function() {
callback(null, result);
});
});
});
async.parallel(streams_to_process, function(err, results) {
// all done
});
Internally, async.parallel uses a counter captured in a closure to keep track of when all async processes (in this case the 'end' events) are done.
There are other libraries for this. Most promise libraries for example provide an .all() method that works the same way - internally keeping track of a counter value and firing the .then() callback when all is done.