node is it possible to do if statements on events? - node.js

Kind of like this?
if (this.on('pipe',function () {
return true
}){
//do something if piped
}else{
//do something if not piped
}
Because I want to do something different depending on whether or not something is piped to the function or not.
I'm guessing that won't work however because of how async node is, but I need something like that at least.
The main thing is I need something to run either OR but not both, if I were to implement a callback it won't work exactly like I want it to because whatever code I put after the this.on will still run, i need it to not run if this.on fires.
EDIT: Would process.nextTick() be what I need?

I can't immagine the real situation where it's needed. I think you try to do something like this:
function mainContextFunction() {
var isPiped = false;
this.on('pipe', function(){isPiped = true;});
function delayedExecution() {
if (isPiped) ...;
else ...
}
setTimeout(delayedExecution, 1000);
}
mainContextFunction();

Ok, what I needed to do was Defer it to the next stack process with process.nextTick() so that it executed AFTER the .on callback was executed. so it's like this:
upload = function (path,file,callback){
this.notpiped = true
this.on('pipe',function () {
this.notpiped = false
})
process.nextTick(function() {
if(this.notpipe){
cback(path,file,callback)
}
})
this.end = function () {
//handle piped data, eg, parse it, or set it or whatever and then use cback
}
}
upload.prototype._write = (chunk, encoding, callback){
this.data = this.data + chunk
}
so now this .end will fire like normal ONLY if .pipe gets called on it BUT if pipe doesn't get called then .end will never fire so it's ok to do it like this.
I can now have a function that can have data streamed to it, OR directly used depending on circumstances.
My actual function I'm using does a bit more then this and looks a little different but the concept is the same.

Related

nodejs async function how to?

So I am not sure how to convert a function that I have that is built synchronously but uses asynchronous calls.
do_thing = () => {
var N = new Thing(); //sync
N.do_that(); // calls fs.readFile() and does some stuff with data :async
this.array.push(N); // sync but does not affect anything
this.save(); // calls fs.writeFile() but needs info from N that is not created yet as N.do_that() is not done
}
I am not sure how to make it so when N.do_that() is done it then calls this.save(). I do not want to use fs.readFileSync() or fs.writeFileSync(). I would like to know how to something like:
N.do_that().then( this.save() );
Ok I figured it out. Inside my N.do_that(); I added a callback, something like so:
do_that = (callback) => {
fs.readFile("file", (err, fd) => {
// do stuff with fd
callback();
return;
});
}
then rather than calling :
N.do_that();
array.push(N);
this.save();
I did
N.do_that(() => {
array.push(N);
this.save();
};
You could use a 3rd-party, open source tool that already gives you Promisified versions to help! One Google search revealed: https://www.npmjs.com/package/fs-promise
Otherwise, you can promisify the method yourself using tips from https://stackoverflow.com/a/34642827/3814251.
(Alternatively, use callbacks, which you've posted in your own answer.)

Execute when both(!) events fire .on('end')

I have a node app that reads two files as streams. I use event.on('end') to then work with the results. The problem is I don't really know how I can wait for BOTH events to trigger 'end'.
What I have now is:
reader1.on('end', function(){
reader2.on('end',function(){
doSomething();
});
});
With small files this works, but if one of the files is very large the app aborts.
Your execution logic is somewhat flawed. You ought to do something like this instead
var checklist = [];
// checklist will contain sort of a counter
function reader_end(){
if(checklist.length == 2 )
// doSomething only if both have been added to the checklist
doSomething();
}
reader1.on('end', function() {
checklist.push('reader1');
// increment the counter
reader_end();
});
reader2.on('end', function() {
checklist.push('reader2');
reader_end();
});
Although there are libraries to better handle this sort of stuff, like Async and Promises.
With Async you'll need to use compose
var r12_done = async.compose(reader1.on, reader2.on);
r12_done('end', function(){
doSomething();
});
Edit: I just noticed that since probably reader1.on is a Stream 'end' event which doesn't have the standard callback argument signature of (err, results), this probably won't work. In that case you should just go with Promise.
With Promise you'll need to first Promisify and then join
var reader1Promise = Promise.promisify(reader1.on)('end');
var reader2Promise = Promise.promisify(reader2.on)('end');
var reader12Promise = Promise.join(reader1Promise, reader1Promise);
reader12Promise.then(function(){
doSomething();
});

Function returning data from db

I am a newbie to node js and I am using mongoose for my models.
I have a function namde check which has a isNameThere function which receives name string as parameter in it. It checks the Db and looks for the name string which is provided if user exist in this name this.isNameThere will return true
var check= function()
{
this.nameIsThere = false;
this.isNameThere= function(name){
userModel.find({firstname: name},function(err,result){
if(result)
{
this.nameIsThere= true;
}
})
return this.nameIsThere;
}
}
Even if the name exist as you guess the code above will return false because the nature of asynchronous programming. Is there a way to execute the return isNameThere after userModel.find executes. Or any other solution for this situation. Thanks All.
Careful with the semicolons, you forgot some. It´s also good practice in JavaScript to place opening brackets right next to the function header and not in the next line.
You can encapsulate the DB call in a function like this:
function checkForName (callback) {
userModel.find({firstname: name}, callback);
}
checkForName(function (err, result) {
if (result) {
nameIsThere = true;
//do something else
...
}
});
After all, it IS anychronous, so you will not get any synchronous return value.
There´s also another way: Promises. Some libraries for you to check out:
https://github.com/caolan/async
https://github.com/kriskowal/q

Conditionally call async function in Node

I have the following example code - the first part can result in an async call or not - either way it should continue. I cannot put the rest of the code within the async callback since it needs to run when condition is false. So how to do this?
if(condition) {
someAsyncRequest(function(error, result)) {
//do something then continue
}
}
//do this next whether condition is true or not
I assume that putting the code to come after in a function might be the way to go and call that function within the async call above or on an else call if condition is false - but is there an alternative way that doesn't require me breaking it up in functions?
A library I've used in Node quite often is Async (https://github.com/caolan/async). Last I checked this also has support for the browser so you should be able to npm / concat / minify this in your distribution. If you're using this on server-side only you should consider https://github.com/continuationlabs/insync, which is a slightly improved version of Async, with some of the browser support removed.
One of the common patterns I use when using conditional async calls is populate an array with the functions I want to use in order and pass that to async.waterfall.
I've included an example below.
var tasks = [];
if (conditionOne) {
tasks.push(functionOne);
}
if (conditionTwo) {
tasks.push(functionTwo);
}
if (conditionThree) {
tasks.push(functionThree);
}
async.waterfall(tasks, function (err, result) {
// do something with the result.
// if any functions in the task throws an error, this function is
// immediately called with err == <that error>
});
var functionOne = function(callback) {
// do something
// callback(null, some_result);
};
var functionTwo = function(previousResult, callback) {
// do something with previous result if needed
// callback(null, previousResult, some_result);
};
var functionThree = function(previousResult, callback) {
// do something with previous result if needed
// callback(null, some_result);
};
Of course you could use promises instead. In either case I like to avoid nesting callbacks by using async or promises.
Some of the things you can avoid by NOT using nested callbacks are variable collision, hoisting bugs, "marching" to the right > > > >, hard to read code, etc.
Just declare some other function to be run whenever you need it :
var otherFunc = function() {
//do this next whether condition is true or not
}
if(condition) {
someAsyncRequest(function(error, result)) {
//do something then continue
otherFunc();
}
} else {
otherFunc();
}
Just an another way to do it, this is how I abstracted the pattern. There might be some libraries (promises?) that handle the same thing.
function conditional(condition, conditional_fun, callback) {
if(condition)
return conditional_fun(callback);
return callback();
}
And then at the code you can write
conditional(something === undefined,
function(callback) {
fetch_that_something_async(function() {
callback();
});
},
function() {
/// ... This is where your code would continue
});
I would recommend using clojurescript which has an awesome core-async library which makes life super easy when dealing with async calls.
In your case, you would write something like this:
(go
(when condition
(<! (someAsyncRequest)))
(otherCodeToHappenWhetherConditionIsTrueOrNot))
Note the go macro which will cause the body to run asynchronously, and the <! function which will block until the async function will return. Due to the <! function being inside the when condition, it will only block if the condition is true.

node.js scope problems?

I'm working on making a script with node.js for setting up my dzen2 in i3, and haven't really used node for anything like this before.
I need the geometry of the screen to start with, which I can get with something like this:
geometry = getGeo();
function getGeo() {
var sh = require('child_process').exec("i3-msg -t get_outputs",
function(error, stdout, stderr) {
var out = JSON.parse(stdout);
return out[0].rect; //this is the geometry, {"x":0, "y":0, "width":1280, "height":768}
});
};
console.log(geometry);
console.log is logging undefined.
I'm not sure what the proper way to do this is, my brain is tired.
You can't return from the callback function since is async.
Rather write another function and pass the callback object to it.
function getGeo() {
var sh = require('child_process').exec("i3-msg -t get_outputs",
function(error, stdout, stderr) {
var out = JSON.parse(stdout);
getRect(return out[0].rect);
});
};
function getRect(rect) {
// Utilize rect here...
}
You never return a value from getGeo(), you're returning a function from the anonymous function within it. But because of the async nature of the .exec() call, you can't return the value. You can put the console.log into the callback function, but that may not be where you want to use it in your real program.

Resources