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);
Related
I'm not making any calls to any server. I'm simply looping over an object and making some simple comparisons on the current item. I want to be able to use return instead of nesting my code inside a callback. By my current understanding of node.js, the below code should execute immediately and return the boolean.
Example:
function validate() {
var error = false;
var items = {
'item1': 'value1',
'item2': 'value2'
};
var eachItem = function(item, key, next) {
// do some simple comparisons
if (item !== 'value3') {error = true;}
next();
};
async.forEachOf(items, eachItem, function() {
// I prefer not to use callback(error), error is defined here
console.log('End Validate', error);
return error;
});
}
var thisError = validate();
console.log('After Validate', thisError); // thisError is undefined
The above does not work. I'm thinking because I'm using async.forEachOf. validate() is always undefined. However, when debugging, I notice that the boolean is defined before the next code is ran ('End Validate' shows up, then 'After Validate' does, which is the correct order of execution). Looks like it's simply not returning. Is there any way to return the boolean from the function in my above example without using a callback?
I do not want to use a for...in because I love the way async references the current item in the collection, and if I never need to, I can easily change my code with a callback in case I'm actually doing async operations.
Habits. The answer turns out to be very simple. I needed to define the return as the last line in the validate() function. It cannot be inside the async.forEachOf method.
The below is a working example.
function validate() {
var error = false;
var items = {
'item1': 'value1',
'item2': 'value2'
};
var eachItem = function(item, key, next) {
// do some simple comparisons
if (item !== 'value3') {error = true;}
next();
};
async.forEachOf(items, eachItem, function() {
// I prefer not to use callback(error), error is defined here
console.log('End Validate', error);
});
return error;
}
var thisError = validate();
console.log('After Validate', thisError); // thisError is defined
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")
})
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");
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).
Consider this code:
var async = require('async');
var a = function()
{
console.log("Hello ");
};
var b = function()
{
console.log("World");
};
async.series(
[
a,b
]
);
Output is
Hello
Why is World not part of the output?
The async.series function passes one callback to each of the methods that must be called before the next one is called. If you change your functions a and b to call the function it will work.
function a(done){
console.log('hello');
done(null, null); // err, value
}
function b(done){
console.log('world');
done(null, null); // err, value
}
For each method called in series it is passed a callback method which must be run, which you are ignoring in your example.
The docs say:
tasks - An array or object containing functions to run, each function
is passed a callback(err, result) it must call on completion with an
error err (which can be null) and an optional result value.
The reason why your code is stopping after the first method is that the callback isn't being run, and series assumed an error occurred and stopped running.
To fix this, you have to rewrite each method along these lines:
var b = function(callback)
{
console.log("World");
callback(null, null) // error, errorValue
};