This might be an awful question but I'm trying to use Promise-IO with nodeJS. I'm trying to use the seq function. I have something like the following.
seq = require("promised-io/promise").seq,
var functions= new Array(function1, function2);
seq(functions, startingDataObject)
In function1 I have something like the following.
function function1(startingDataObject) {
var deferred = new Deferred();
when(function3(startingDataObject),
function (returnedData) {
//Some logic
deferred.resolve(returnedData);
},
function (err) {
console.log(err);
throw err;
});
deferred.promise;
}
What i see happening is function2 is getting fired right after deferred.promise. I'm not sure if my google skills are lacking but I don't seem to see many examples on how to use this method. So my question is how do i use Promise-IO to make sync sequential calls.
https://github.com/kriszyp/promised-io#seq
Thanks
Found the issue. I was missing a return deferred.promise in function1. The example above worked perfectly.
Related
I am trying to run a mongoose query and write it to the console without installing yet another library like bluebird. I have been unable to find this in the documentation.
Here is the query:
function activityH(){
return setRecords.find({'item.title': 'marzipan'}
, 'item.title item.quantity').exec();
}
And the context in which I am calling it:
....[a bunch of promises].then(activityF).then(activityG).then(activityH).then(function(doc){console.log(doc);});
All of the prior activities are completing, but nothing is logging even though my query should have results. I feel this is a very basic question but I have looked for hours trying to find a solution and if this is a duplicate, the original answer is very hard to search for!
Do I absolutely need bluebird to do this? E.g. this blog post
Thank you
You could write a little logging function wrapper to help you out. Something like
function log(data) {
console.log(data);
return data;
}
And then add it your Promise chain.
....[a bunch of promises]
.then(log)
.then(activityF)
.then(log)
.then(activityG)
.then(log)
.then(activityH)
.then(log)
If you want some default messaging you could also pass a message string
function log(msg) {
return function(data) {
console.log(msg, data);
return data;
}
}
And then would add to the chain like:
activityA()
.then(log('activityA'))
.then(activityB)
.then(log('activityB'))
NOTE: I edited this question to more accurately show the problem, rather than delete and rewrite it. Hope that's OK.
For the following code:
var Q = require('q');
function first (){
var d = Q.defer();
setTimeout(function(){
d.resolve([]);
}, 1000);
return d.promise;
}
function second(v){
sdf;
console.log("hi")
}
first()
.then(second);
How can I determine that there is a ReferenceError in there? Is the only option to add a second function argument in the then call?
Even though it's not recommended, I tried using process.on('uncaughtException') but to no avail.
Thanks!
Rewrite your final call like this:
function errorHandler(err) {
console.log('You had an error, ' + err);
}
first
.then(second, errorHandler);
The promise captures any exceptions that throw within it, you need to explicitly handle it.
A variation that's q specific would be:
first
.then(second)
.fail(errorHandler);
You may consider this easier to read.
I think it may be appropriate to catch the error before the declaration of the contract object. So something like this:
map(locations, function(loc) {
if(!loc.ClientId) {
console.log("Error: loc.ClientId is undefined");
} else {
var contract = {
"clientName": clients[loc.ClientId][0]
}
...
}
})
Here the error is logged to console when loc.ClientId is undefined.
It really depends what your stack trace looks like. If you're using express or restify, for example, you may actually need to listen for the uncaughtException event on your server object. The error is normally not lost; put something like this into a sample JS file:
null.f();
and you'll see a TypeError thrown, as you are expecting.
If you're not sure of the stack, log it:
console.log(new Error("this is my stack").stack);
I have the following problem with mongodb-native. I have a function whose purpose is to return some element from db.
function get(){
db.collection('test').findOne({...},{...},function(err, doc){
// my doc is here
});
// but here my doc is undefined
// so I can not return it
return doc;
}
So due to asynchroneous nature of node, I can not get my doc back. So how can I make it synchroneous (or is there any other way)?
I need for my single page app. So when my client does some action, ajax request is sent which is handled by get function. This function has to send back JSON.
The answer is to have your code work asynchroneous, that is the whole concept of JavaScript.
Thus if you have something like this in your synchroneous program:
function get() {
db.collection('test').findOne({...},{...},function(err,doc) {
});
return doc;
}
var doc = get();
console.log(doc);
You can refactor it into:
function printToConsole(err, doc) {
console.log(doc);
}
function get(callback) {
db.collection('test').findOne({...},{...},callback);
}
get(printToConsole);
It is not a unique solution, there are other workflows. Some like promises will make your code flatter.
But my personal suggestion, is to initially learn how to code asynchroneous code without supporting libraries. Initially it feels like a pain, just give it some time and you will start enjoying the idea.
I'm learning node.js coming from a PHP background with a limited JavaScript level. I think I got over now the change of mindset implied by the asynchronous approach. And I love it.
But, as many others before me, I quickly understood the concrete meaning of the "pyramid of doom".
So I build these little 'dummy' route and view to understand how to properly use Async.js. I just spend the last 5 hours writing the following code (rewritten of course tens of times). It works, but I wonder how I could go further and made this code more simple (less verbose, easier to read and maintain).
I found many resources on the web and especially here, but always by bits of info here and there.
I'm guessing at this point that I should use "bind" and "this" with async.apply to make to shorten the 2 last functions called by the waterfall.
The issue is to get the object "db" defined so I can use the "collection" method on it (for the second function).
I really searched an example in Google, but it's surprising that you don't get straightforward examples looking for "async waterfall bind" (as well as many keyword variations I tried). There are answers of course but none seems relevant to this particular issue... ore, quite possibly, I haven't understood them.
Can someone help me on this? I'll be quite grateful.
app.get('/dummy',
function(req, res) {
var MongoClient = require('mongodb').MongoClient;
async.waterfall(
[
async.apply(MongoClient.connect, 'mongodb://localhost:27017/mybdd'),
function(db, callback) {
db.collection('myCollection', callback);
},
function(collection, callback) {
collection.find().sort({"key":-1}).limit(10).toArray(callback);
}
], function(err, results) {
if (err) console.log('Error :', err);
else { res.render('dummy.jade', { title:'dummy', results: results} ); }
}
);
}
);
If you're using the mongodb JS Driver, then this should work:
async.waterfall(
[
function (cb) {
new MongoClient(...)
.connect('mongodb://localhost:27017/mybdd', cb);
},
function (db, callback) {
db.collection('myCollection', callback);
},
...
Alternatively, if you want to use async.apply, just pass an instance of MongoClient
async.apply(new MongoClient(...).connect, 'mongodb://localhost:27017/mybdd')
I've recently created a simple abstraction named WaitFor to call async functions in sync mode (based on Fibers): https://github.com/luciotato/waitfor
I'm not familiar with mongodb client, so i'll be mostly guessing what you're trying to do:
using WaitFor your code will be:
var MongoClient = require('mongodb').MongoClient;
var wait = require('waitfor');
app.get('/dummy', function(req, res) {
// handle request in a Fiber, keep node spinning
wait.launchFiber(handleDummy,req,res)
}
);
function handleDummy(req, res) {
try {
var db = wait.for(MongoClient.connect, 'mongodb://localhost:27017/mybdd');
var collection = wait.forMethod(db,'collection','myCollection');
var results = wait.forMethod(collection.,'sort',{"key":-1}).toArray();
res.render('dummy.jade', { title:'dummy', results: results} );
}
catch(err) {
res.render('error.jade', { title:'error', message: err.message} );
}
};
I'm using Mongoose with Node.js and have the following code that will call the callback after all the save() calls has finished. However, I feel that this is a very dirty way of doing it and would like to see the proper way to get this done.
function setup(callback) {
// Clear the DB and load fixtures
Account.remove({}, addFixtureData);
function addFixtureData() {
// Load the fixtures
fs.readFile('./fixtures/account.json', 'utf8', function(err, data) {
if (err) { throw err; }
var jsonData = JSON.parse(data);
var count = 0;
jsonData.forEach(function(json) {
count++;
var account = new Account(json);
account.save(function(err) {
if (err) { throw err; }
if (--count == 0 && callback) callback();
});
});
});
}
}
You can clean up the code a bit by using a library like async or Step.
Also, I've written a small module that handles loading fixtures for you, so you just do:
var fixtures = require('./mongoose-fixtures');
fixtures.load('./fixtures/account.json', function(err) {
//Fixtures loaded, you're ready to go
};
Github:
https://github.com/powmedia/mongoose-fixtures
It will also load a directory of fixture files, or objects.
I did a talk about common asyncronous patterns (serial and parallel) and ways to solve them:
https://github.com/masylum/i-love-async
I hope its useful.
I've recently created simpler abstraction called wait.for to call async functions in sync mode (based on Fibers). It's at an early stage but works. It is at:
https://github.com/luciotato/waitfor
Using wait.for, you can call any standard nodejs async function, as if it were a sync function, without blocking node's event loop. You can code sequentially when you need it.
using wait.for your code will be:
//in a fiber
function setup(callback) {
// Clear the DB and load fixtures
wait.for(Account.remove,{});
// Load the fixtures
var data = wait.for(fs.readFile,'./fixtures/account.json', 'utf8');
var jsonData = JSON.parse(data);
jsonData.forEach(function(json) {
var account = new Account(json);
wait.forMethod(account,'save');
}
callback();
}
That's actually the proper way of doing it, more or less. What you're doing there is a parallel loop. You can abstract it into it's own "async parallel foreach" function if you want (and many do), but that's really the only way of doing a parallel loop.
Depending on what you intended, one thing that could be done differently is the error handling. Because you're throwing, if there's a single error, that callback will never get executed (count won't be decremented). So it might be better to do:
account.save(function(err) {
if (err) return callback(err);
if (!--count) callback();
});
And handle the error in the callback. It's better node-convention-wise.
I would also change another thing to save you the trouble of incrementing count on every iteration:
var jsonData = JSON.parse(data)
, count = jsonData.length;
jsonData.forEach(function(json) {
var account = new Account(json);
account.save(function(err) {
if (err) return callback(err);
if (!--count) callback();
});
});
If you are already using underscore.js anywhere in your project, you can leverage the after method. You need to know how many async calls will be out there in advance, but aside from that it's a pretty elegant solution.