I'm trying to work with synchronize.js to run some functions that must be executed synchronously.
I've read something about it here and here.
To try it out, I've created the following code
var sync = require('synchronize');
var fiber = sync.fiber;
var await = sync.await;
var defer = sync.defer;
function function1(){
console.log("Executing function 1")
}
sync.fiber(function() {
console.log('Before');
var step1 = await(setTimeout(function1, 1000, defer()));
var step2 = console.log('After');
});
console.log('Outside');
Logic tells me the output should be
Before
Outside
Executing function 1
After
But what I get is
Before
Outside
Executing function 1
Somehow, step2 is not being executed and I can't figure out why.
I've never used this plugin before but try this:
var sync = require('synchronize');
var fiber = sync.fiber;
var await = sync.await;
var defer = sync.defer;
function function1(callback){
// defer expects this to be asynchronous (so it needs to execute a callback)
console.log("Executing function 1")
callback();
}
sync.fiber(function() {
console.log('Before');
var step1 = await(setTimeout(function1, 1000, defer()));
var step2 = console.log('After');
});
console.log('Outside');
Basically I think calling defer prematurely (before the callback is executed) causes it to hang.
Edit:
After reading the documentation I now realize that defer creates a callback function. That would mean it's hanging because the callback it creates is never called. Let me know if this works.
Related
I know what debounce does. I'd like to trigger it in node (by running a script with #!/usr/bin/env node), but I'm having trouble.
The code below should:
Make doThingAfterDelay() which runs a simply function after it has been called once and not been called again for 100ms.
Run doThingAfterDelay()
Sleep (asynchronously) for 15 seconds, giving doThingAfterDelay() time to debounce and therefore execute.
However it doesn't work:
var log = console.log.bind(console),
_ = require('lodash')
var doThingAfterDelay = _.debounce(function(){
return 'foo'
}, 100);
log(doThingAfterDelay());
setTimeout(function(){
log('Sleeping')
}, 15 * 1000)
It returns:
undefined
Sleeping
I expected:
foo
Sleeping
How can I make the debounced function run?
edit: I can get the desired output with:
var log = console.log.bind(console),
_ = require('lodash')
var doThingAfterDelay= _.debounce(function(){
log('foo')
}, 100);
doThingAfterDelay('one', 'two');
setTimeout(function(){
log('Sleeping')
}, 15 * 1000)
But I do not understand why - and it is important that doThingAfterDelay() returns a real value.
If you have a look at source code of the debounce function you can find that it uses setTimeout under the hood and therefore has the same mechanic. You can use a callback or Promise to pass value after debounced function will be executed(also if you are using Promise you could make your code look more synchronous with async/await).
var log = console.log.bind(console),
_ = require('lodash')
var delayedResults = new Promise(function(resolve) {
_.debounce(function(){
resolve('foo');
}, 100)();
});
var start = async function(){
log(await delayedResults )
}
start()
Dears ,
How can i run promises in nodejs sequentially , in the following example am looping through array of hours then for each fetched hour get result from the database , the issue here : am getting results but i want it sequentially same order that i got hours .
angular.forEach(SharedVar.getCategories(), function (h) {
t = h.split('-', 2);
t = t[0];
RESTApi.getAnswerdCallsByHour(t).then(function (answerdTotal) {
$scope.answerdCallsTotalByHour.push(answerdTotal);
var d = SharedVar.getDataS();
d[count] = answerdTotal;
SharedVar.setDataS(d);
count++;
});
});
Thanks ,
var promise = Promise.resolve(); // make an empty promise in the way you do it with your promise library
angular.forEach(SharedVar.getCategories(), function (h) {
promise.then(function() {
return RESTApi.getAnswerdCallsByHour(t).then(function (answerdTotal) {});
});
});
The way to do it sequently would be to do one Request and do the next request inside the promise.
I think the better approach by far is to extend your SharedVar.setDataS(d) function in a way, that it does not depend on getting the data sequentially. Like having a SharedVar.setDataS(d, index) and using the config var in your $http.get (or whatever) functioncall inside your RESTApi to promote that index all the way to the promise.
If your RESTApi looks like this:
var RESTApi = {
getAnswerdCallsByHour : function(hour) {
var url = "bla.com/myservice?hour=" + hour;
return $http.get(url).data;
}
// Some other Methods...
Then you need a way to pass something to "reorder" your Data when it arrives asynchronously, this could be a index you count up or in your case maybe the hour Variable:
var RESTApi = {
getAnswerdCallsByHour : function(hour) {
var url = "bla.com/myservice?hour=" + hour;
var config = [];
config.hour = hour;
return $http.get(url, config); // Return the promise not just data or a specific field
}
// Some other Methods...
Now when your promise is fullfiled you can access your "hour" Variable like so:
var d = SharedVar.getDataS();
d[promise.config.hour] = promise.data;
SharedVar.setDataS(d);
Now you know what piece of data correlates to which request and you do not need to recieve Data in order. The last piece only works properly when hours runs sequential from 0 to 23, if that isn't the case you need to:
var RESTApi = {
getAnswerdCallsByHour : function(hour, index) {
var url = "bla.com/myservice?hour=" + hour;
var config = [];
config.index = index;
return $http.get(url, config);
}
// Some other Methods...
...
...
var d = SharedVar.getDataS();
d[promise.config.index] = promise.data;
SharedVar.setDataS(d);
Safari's answer is how I typically handle this. (Sorry, I don't have enough rep to comment yet...) You were experiencing problems with it because the example provided does not capture and use the new promise in subsequent loops. See my comments on the slightly modified version here:
var promise = Promise.resolve();
angular.forEach(SharedVar.getCategories(), function (h) {
t = h.split('-', 2);
t = t[0];
// You must capture the new promise here; the next loop will wait
// for the promise returned from getAnswerdCallsByHour to resolve.
promise = promise.then(function() {
// Halt downstream promises until this returned promises finishes
return RESTApi.getAnswerdCallsByHour(t).then(function (answerdTotal) {
$scope.answerdCallsTotalByHour.push(answerdTotal);
var d = SharedVar.getDataS();
d[count] = answerdTotal;
SharedVar.setDataS(d);
count++;
});
});
});
Given Node.js boasts of asynchronous event driven model,
I was expecting, I should be able to write any Nodejs function,
e.g as simple as going through a loop, e.g IamLooper() below,
which might or might not involve file I/O and then pass that looping function to a mother nodeJs function e.g Invoke(),to which I also pass another call back functiont e.g happyend() below.
My expectation was after IamLooper is finished ,happyend () will be invoked by the NodeJs supplied function .
e.g :
==>
gdata =[];
function IamLooper() {
var pi = Array;
for (var ii = 0 ; ii <4 ; ii ++)
{
pi[ii] = 13* ii;;
gdata.push(ii);
}
console.log("looper done -tell the callback") ;
}
function happyend() { console.log("looper says done");}
I want to invoke IamLooper() and supply the happyend at time of invocation.
i.e. I am looking for a ready made node function e.g Invoke, which can be called like this:
Invoke(IamLooper(), happyend());
if(gdata.length > 0) {console.log("looping has started");}
In essence Invoke should do the same for any two functions I supply to it so that we have just a working template of a callback execution strategy.
Also the Invoke being executed async, my program progresses beyond Invoke before it finishes.
Is my expectation is misguided ? Can any one give me some guidance here.
If you are looking for a preexisting way of easily doing callbacks in node, you should use event emitters (https://nodejs.org/api/events.html):
var EventEmitter = require('events').EventEmitter;
var eventExample = new EventEmitter;
//You can create event listeners:
eventExample.on('anEvent', function(someData){
//Do something with someData
});
//To trigger an event listener you must emit:
eventExample.emit('anEvent', someData);
With your code, it'd look something like this:
var EventEmitter = require('events').EventEmitter;
var looper = new EventEmitter;
looper.on('invoke', function(data){
var callFunction = data.callFunction;
var finishFunction = data.finishFunction;
var callParameters = data.callParameters;
var finishParameters = data.finishParameters;
if(callParameters == null){
callFunction({callbackPara: finishParameters, callbackFunction: finishFunction});
}
else{
callFunction(callParameters, {callbackParameters: finishParameters, callbackFunction: finishFunction});
}
});
looper.on('finish', function(data){
var finishFunction = data.callbackFunction;
var parameters = data.callbackParameters;
if(parameters == null){
finishFunction();
}
else{
finishFunction(parameters);
}
});
gdata =[];
function IamLooper(g, callback){
var pi = Array;
for (var ii = 0 ; ii <4 ; ii ++){
pi[ii] = 13* ii;;
g.push(ii);
}
looper.emit('finish', callback);
}
function happyend() { console.log("looper says done");}
And then call it like:
looper.emit('invoke', {callFunction: IamLooper, finishFunction: happyend, callParameters: gdata, finishParameters: null});
You can also always do normal callbacks:
gdata =[];
function IamLooper(g, callback){
var pi = Array;
for (var ii = 0 ; ii <4 ; ii ++){
pi[ii] = 13* ii;;
g.push(ii);
}
callback();
}
IamLooper(gdata, function(){ console.log("looper says done");}
I have to do an operation that calculate for me something, but I can't use the result of it, because I always stay in a wait state, in fact in my terminal remains in execution my program until I enter ctrl+C.
I have a main in nodejs for my program where I need to use my result calculated in a module.
var myJSONClient = {
"nombre" : "<nombre_cliente>",
"intervalo" : [0,0]
};
var intervalo = gestionar.gestion(myJSONClient,vector_intervalo);
console.log("intervalo: "+intervalo); //return undefined
And this is the module
var gestion = function(myJSON,vector_intervalo) {
var dburl = 'localhost/mongoapp';
var collection = ['clientes'];
var db = require('mongojs').connect(dburl, collection );
var intervalo_final;
function cliente(nombre, intervalo){
this.nombre = nombre;
this.intervalo = intervalo;
}
var cliente1 = new cliente(myJSON.nombre,myJSON.intervalo);
db.clientes.save(cliente1, function(err, saveCliente){
if (err || !saveCliente) console.log("Client "+cliente1.nombre+" not saved Error: "+err);
else console.log("Client "+saveCliente.nombre+" saved");
intervalo_final = calculate(vector_intervalo);
console.log(intervalo_final); //here I can see the right content of the variable intervalo_final
});
console.log(intervalo_final); //this is not executed
return intervalo_final;
}
exports.gestion = gestion;
Welcome to the async world! :)
First of all, you aren't doing blocking operations in Node. Actually, networking in Node is fully asynchronous.
The part you state the console.log works it's because the callback function of the db.clientes.save call. That callback states your mongo save has finished.
What asynchronous networking means?
It means that your save will be processed sometime in the future. The script will not wait for the response to continue the code. The console.log right after the save call will be executed soon as it's reached.
As for the "wait state" of your script, that it never ends, you should take a look at this question. There's the answer.
this is my code.
var fs = require('fs')
var test = readafile('file.txt', function(returnValue) {
console.log(returnValue);
test = returnValue;
});
console.log(test);
function readafile(filepath,callback){
var attachment_path = filepath;
fs.readFile(attachment_path, function(err,data){
var attachment_encoded = new Buffer(data, 'binary').toString('base64');
callback(attachment_encoded);
});
}
In that if i need that return value of that function in variable test means how to achieve that ?
In that console.log(test) it says undefined.
since it is a callback function.
How to get it properly ?
You can't really expect getting a synchronous behavior (like getting a return value) with asynchronous code. You can use fs.readFileSync to avoid the asynchronous aspect or just use your value inside your callback.
Otherwise the async module could help you out.