I am trying to log time for something. The general code looks like so:
var stream = db.call.stream();
stream.on('data', function () {
if (first) {
console.time('doSomething');
}
stream.pause();
doSomethingWithData(data);
if (stopCondition) {
console.timeEnd('doSomething');
done();
} else {
stream.resume();
}
});
I would like to know if the call to console.time is blocking or asynchronous? I could not find this in the docs.
According to the source code of console.time and console.timeEnd,
Console.prototype.time = function(label) {
this._times[label] = Date.now();
};
Console.prototype.timeEnd = function(label) {
var time = this._times[label];
if (!time) {
throw new Error('No such label: ' + label);
}
var duration = Date.now() - time;
this.log('%s: %dms', label, duration);
};
They just store the starting time against the label and calculate the time elapsed since the label timed.
They don't do anything asynchronously.
Note: In node.js, if a function is asynchronous, it will accept callback as one of the parameters.
Related
I have this function in my Backbone view for creating a new object through an API in the backend:
// *** called when remote hardware signal triggered
createConference: function () {
var self = this;
console.log("ScheduleLocationArea.js - createConference() ")
const startTime = performance.now();
this.sysLocation.create().then((response) => {
self.model.collection.add(response);
});
const duration = performance.now() - startTime;
console.log(`PERFORMANACE CHECK: ScheduleLocationArea.js - the function createConference() took ${duration}ms`);
},
It calling this function:
// called from within createConference
async create() {
console.log("Location.js - create() ")
const startTime = performance.now();
return await this.sync('create', this, {
url: this.create.url(this.id)
}, { silent: true });
const duration = performance.now() - startTime;
console.log(`PERFORMANACE CHECK: Location.js - the function create() took ${duration}ms`);
},
As you can see, I'm trying to check performance issues.
But for some reason that I cant figure out, it's not finishing the create() function. I never see the PERFORMANACE CHECK for that function.
Here is my console output:
ScheduleLocationArea.js - createConference()
Location.js:22 Location.js - create()
ScheduleLocationArea.js:269 PERFORMANACE CHECK: ScheduleLocationArea.js - the function createConference() took 1.7000000476837158ms
The browser writes out all the above console messages really fast.
And even though it says it only took 1.7ms...it actually takes about 3 seconds.
So I can't figure out whats taking so long and why it's not writing out the performance numbers for the create() function.
Is there something I'm doing wrong?
Thanks!
Change your code from:
// called from within createConference
async create() {
console.log("Location.js - create() ")
const startTime = performance.now();
return await this.sync('create', this, {
url: this.create.url(this.id)
}, { silent: true });
const duration = performance.now() - startTime;
console.log(`PERFORMANACE CHECK: Location.js - the function create() took ${duration}ms`);
},
to
// called from within createConference
async create() {
console.log("Location.js - create() ")
const startTime = performance.now();
const newUrl = await this.sync('create', this, {
url: this.create.url(this.id)
}, { silent: true });
const duration = performance.now() - startTime;
console.log(`PERFORMANACE CHECK: Location.js - the function create() took ${duration}ms`);
return newUrl;
},
This will allow your function to show the performance logs before returning the created value.
You are returning from your function before calling console.log in your first snippet. Any code following a return statement isn't run:
// called from within createConference
async create() {
console.log("Location.js - create() ")
const startTime = performance.now();
return await this.sync('create', this, {
url: this.create.url(this.id)
}, { silent: true });
// this following code never runs as screate(0 has returned already
const duration = performance.now() - startTime;
console.log(`PERFORMANACE CHECK: Location.js - the function create() took ${duration}ms`);
},
I'm sorry if this question as already been answered and I hope I'm not breaking any SO rule, if so, in advance I apologise...
I was wondering what was the best way to handle a request limiter? I've seen a bunch of throttles and rate-limiters online but I'm not sure how or if it could apply in my case.
I'm doing a bunch of [OUTGOING] request-promises based on an Array and on a server I can only make 90 request per minute. My request-promises are generated by this command: return Promise.all(array.map(request)).
I was thinking to handle it like this:
var i = 0;
return rp({
url: uri,
json: true,
}).then((data) => {
if (i <=90) {
i ++;
return data;
} else {
return i;
}
});
but I'm not sure if it will be a really effective way to handle it plus, I'm not sure how to handle the time relation yet... :S
Thanks in advance for your help and sorry I'm still a huge beginner...
You can use setInterval. Check out the documentation here.
var requestCount = 0;
setInterval(function(){
// Every 60 seconds, reset the count
requestCount = 0;
}, 60000);
// There needs to be an additional check before calling rp,
// that checks for requestCount > 90, and returns before starting the request.
rp({
url: uri,
json: true,
})
.then((data) => {
requestCount++;
return data;
});
If the requests are started from different code parts, it might be useful to implement sth like a server queue which awaits the request until it is allowed to do so. The general handler:
var fromUrl = new Map();
function Server(url, maxPerMinute){
if(fromUrl.has(url)) return fromUrl.get(url);
fromUrl.set(url,this);
this.tld = url;
this.maxPerMinute = maxPerMinute;
this.queue = [];
this.running = false;
}
Server.prototype ={
run(d){
if(this.running && !d) return;
var curr = this.queue.shift();
if(!curr){
this.running = false;
return;
}
var [url,resolve] = curr;
Promise.all([
request(this.tld + url),
new Promise(res => setTimeout(res, 1000*60/this.maxPerMinute)
]).then(([res]) => {
resolve(res);
this.run(true);
});
},
request(url){
return new Promise(res => {
this.queue.push([url,res]);
this.run();
});
}
};
module.exports = Server;
Usable like this:
var google = new require("server")("http://google.com");
google.maxPerMinute = 90;
google.request("/api/v3/hidden/service").then(res => ...);
Probably just do 90 requests per minute. You could use a pseudorecursive promise utilizing function:
function multiRequest(urls, maxPerMinute){
return new Promise(function(cb){
var result = [];
//iterate recursively
(function next(i){
//if finished resolve promise
if(i>=urls.length) return cb(result);
//get all requests
var requests = Promise.all(urls.slice(i,i+maxPerMinute).map(request));
//if the requests are done, add them to result
requests.then(data=>result.push(...data));
//if the requests + one minute done, conginue with next
Promise.all([
requests,
new Promise(res=>setTimeout(res,1000*60))
] ).then(_=>next(i+maxPerMinute))
})(0);
});
}
Use it like this:
multiRequests(["google.com","stackoverflow.com"],90)
.then(([google,so])=>...);
I have a listener to listen for the change of content, once the content modified, it will emit the handler function:
$('#editor').on('onchange', () => changeHandler('...','...'));
function changeHandler(filePath, content){
var ws = fs.createWriteStream(filePath, 'utf8');
ws.write(content);
}
My problem is that the 'onchange' occurs too often, so 'write file' too often handles, it may lost data during the period.
Can someone give any suggestion?
Update
Now I've changed code according the answers below looks like:
this.buffer = null; //used to cache
// once content changed, maybe too often
changeHandler() {
if (this.editor.curOp && this.editor.curOp.command.name) {
var id = $('.nav-items li.active .lk-hosts').attr('data-hosts-id');
var content = this.editor.getValue();
// cache data, not immediately write to file
this.buffer = {id: id, content: content};
}
}
setInterval(()=> {
// means there's data in cache
if (this.buffer !== null) {
let id = this.buffer.id;
let content = this.buffer.content;
// reset cache to null
this.buffer = null;
// write file
this.writeContent(id, content, (err)=> {
})
}
}, 800);
Thanks all answers!
Why not simply build a buffer to collect written text then write to file only when you have a certain number of writes:
$('#editor').on('onchange', () => changeHandler('...','...'));
var writeBuffer = ''; // can also make this an array
var writeBufferSize = 0;
var filePath = 'path_to_file';
var ws = fs.createWriteStream(filePath, 'utf8');
function changeHandler(content){
if (writeBufferSize == SOME_THRESHOLD) {
ws.write(writeBuffer);
writeBuffer = '';
writeBufferSize = 0;
} else {
writeBuffer += content + '\n';
writeBufferSize++;
}
}
If you choose a write buffer threshold that's too big, you might want to delegate the write to some worker thread to be done in parallel, and in this case you can create another temporary write buffer to fill out while the original is being written, then switch the two.
This sample below shows how to make debounced event handling, although it's not node.js code it's same in concept.
// eventEmitter variable to use
var emitter = new EventEmitter();
// dom element change event
$('#editor').on('input', function(event) {
emitter.emit('changeEvent', event.target.value);
});
// event listener, which debounces change event of input
emitter.on('changeEvent', debounce(function(data) {
writeFile('li', data);
}, 1000)); // <== debounce for 1second
// sample emitter, for demo
// we don't have access to nodejs EventEmitter class in Stackoverflow
// don't use in production
function EventEmitter() {
var callbacks = [];
return {
on: function(eventName, fn) {
callbacks.push({
eventName: eventName,
callback: fn
})
},
emit: function(eventName, payload) {
var fn = callbacks.find(function(item) {
return item.eventName === eventName;
});
if (fn) {
fn.callback(payload);
}
}
}
}
// simple logger for demo purpose
// emulates write file
function writeFile(name, content) {
var $elem = $(document.createElement(name));
$elem.text(content);
$('#logger').append($elem);
}
// throttle function - reduces fn call with timeout
// credits: https://remysharp.com/2010/07/21/throttling-function-calls
function debounce(fn, delay) {
var timer = null;
return function() {
var context = this,
args = arguments;
clearTimeout(timer);
timer = setTimeout(function() {
fn.apply(context, args);
}, delay);
};
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea id="editor" placeholder="Enter text, this will emit change event"></textarea>
<p>
Notice the 1sec throttle (write something, pause for 1sec, write again)
</p>
<ul id="logger"></ul>
The debounce function can be also used on textarea change event
// debounce emitting
$('#editor').on('input', debounce(function(event) {
emitter.emit('changeEvent', event.target.value);
}, 1000));
// write file when received event without debounce
emitter.on('changeEvent', function(data){
logElement('li', data);
});
The Underscore library has _.throttle() and _.debounce() functions.
I wrote following code, but it is not returning tDate value, receiving undefined error.
console.log shows result, I think I using global variable wrong way.
seems like after the loop, tDate still not initiated,(inside the loop it is receiving value) how do I define global variable?
function getDates(){
var tDate;
var pool = new ConnectionPool(poolConfig, config);
pool.requestConnection(function (err, connection) {
if(!err) {
var sql = "SELECT MAX(Date) from datatable";
var request = new Request(sql, function(err, rowCount) {
if (err) {
console.log(err);
}
// Release the connection back to the pool.
connection.close();
});
request.on('row', function(columns) {
columns.forEach(function(column) {
if (column.value === null) {
console.log('NULL');
} else {
var date = column.value;
var sDate = new Date(date);
sDate = sDate.toISOString().slice(0,10);
tDate = 'Today= ' + sDate;
console.log(tDate);
}
});
});
connection.on('connect', function(err) {
connection.execSql(request);
});
}
});
return tDate;
}
You're making the classic mistake of the code you've written will be executed in the same order as you see it. It won't. You're binding event listeners, that'll call callback functions if something happens. Only then (in the request.on('row' callback) will the value of tDate be modified.
Requests are, for the most part ASYNCHRONOUS operations, think of it like this:
function testCallback()
{
var someVar = 213;
setTimeout(function()
{
someVar = 'New value';
}, 10000);//10 seconds
return someVar;
}
console.log(testCallback());
This will not take 10 seconds to log, instead it'll log 213 almost immediately, but 10 seconds later, the (now inaccessible) variable someVar will be reassigned.
You can test this by doing:
function testCallback()
{
var valObj = {someVal: 213};
setTimeout(function()
{
valObj.someVal = 'new value';
}, 10000);
return valObj;
}
var o = testCallback();
console.log(o.someVal);//213, still
// wait 10 seconds
console.log(o.someVal);//new value <--
I have replication working in CouchDB and want to update my UI when changes are pushed to the target database. I've read about _changes database API and found the couch.app.db.changes() function in jquery.couch.js However I can't work out how to use the function. I assume I need to set up listener, but my knowledge of Javascript is not yet what it needs to be.
Unfortunately the docs at http://www.couch.io/page/library-jquery-couch-js-database don't even list the changes() function.
Can someone help me here and also let me know what the options param is for.
Here is the code for the function in question:
changes: function(since, options) {
options = options || {};
// set up the promise object within a closure for this handler
var timeout = 100, db = this, active = true,
listeners = [],
promise = {
onChange : function(fun) {
listeners.push(fun);
},
stop : function() {
active = false;
}
};
// call each listener when there is a change
function triggerListeners(resp) {
$.each(listeners, function() {
this(resp);
});
};
// when there is a change, call any listeners, then check for another change
options.success = function(resp) {
timeout = 100;
if (active) {
since = resp.last_seq;
triggerListeners(resp);
getChangesSince();
};
};
options.error = function() {
if (active) {
setTimeout(getChangesSince, timeout);
timeout = timeout * 2;
}
};
// actually make the changes request
function getChangesSince() {
var opts = $.extend({heartbeat : 10 * 1000}, options, {
feed : "longpoll",
since : since
});
ajax(
{url: db.uri + "_changes"+encodeOptions(opts)},
options,
"Error connecting to "+db.uri+"/_changes."
);
}
// start the first request
if (since) {
getChangesSince();
} else {
db.info({
success : function(info) {
since = info.update_seq;
getChangesSince();
}
});
}
return promise;
},
Alternatively you can use longpoll changes feed. Here is one example:
function bind_db_changes(database, callback) {
$.getJSON("/" + database, function(db) {
$.getJSON("/"+ database +
"/_changes?since="+ db.update_seq +"&heartbeat=10000&feed=longpoll",
function(changes) {
if($.isFunction(callback)){
callback.call(this, changes);
bind_db_changes(database, callback);
}
});
});
};
bind_db_changes("test", function(changes){
$('ul').append("<li>"+ changes.last_seq +"</li>");
});
Note that $.couch.db.changes is now in the official documentation:
http://daleharvey.github.com/jquery.couch.js-docs/symbols/%24.couch.db.changes.html
Also a nice example of consuming _changes with the jquery.couch plugin here:
http://bradley-holt.com/2011/07/couchdb-jquery-plugin-reference
what about using the ajax-feateures of jquery?
function get_changes() {
$.getJSON("/path/to/_changes", function(changes) {
$.each(changes, function() {
$("<li>").html(this.text).prependTo(mychanges_div);
});
get_changes();
});
}
setTimeout(get_changes, 1000);
I've been doing work with JS Promises code which enabled mt to understand the CounchDB code I posted above. Here is a sample:
var promise_changes = app.db.changes();
// Add our deferred callback function. We can add as many of these as we want.
promise_changes.onChange( db_changes );
// called whenever this db changes.
function db_changes( resp ) {
console.log( "db_changes: ", resp );
}
Google Chrome goes into a Busy state with long polling, which I hope they will resolve one day.