No output file even though variables are not empty [duplicate] - javascript

This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 5 years ago.
Even though I can clearly see my output in console. I can't write them into a file. There is 1 output file and its undefined-03-02-2017.txt which contains single line '15:33 undefined'.
for (i = 0; i < channelcount; i++) {
messages[i] -= messagesOld[i];
console.log(channels[i] + ' ' + messages[i]);
messages[i] = messagesOld[i];
fs.open('logs/' + channels[i] + '.txt', 'r', function (err, fd) {
if (err && err.code == 'ENOENT') {
fs.writeFile('logs/' + channels[i] + '-' + moment().format('MM-DD-YYYY') + '.txt', moment().format('H:mm') + ' ' + messages[i], function (err) { });
} else {
fs.appendFile('logs/' + channels[i] + '-' + moment().format('MM-DD-YYYY') + '.txt', moment().format('H:mm') + ' ' + messages[i] + '\n', function () { });
}
});
}

fs.open() is an async function. So your entire loop will run before the first callback actually gets called. By that time i equals channelCOount + 1 and channels[ channelCount + 1 ] is undefined.
You can either wrap the callback into a closure, use a let if you can use ES6, or use fs.openSync()

#Pyro, you used writeFile incorrectly. Please see syntax
writeFile(file, data[, options], callback)
you have to use like this
fs.writeFile('logs/' + channels[i] + '-' + moment().format('MM-DD-YYYY') + moment().format('H:mm') + '.txt ' , messages[i], function (err) { });

Related

Data changing before it's used in function

I have been trying to send an email for each expired ticket in the database. Snip of it looks like this:
for (var i = 0; I < rows.length; ++i) {
if (today > new Date(rows[i].end_date)) {
(function(id) {
db.exec('update tickets ' +
'set status="expired" ' +
'where ticket_id= ' + id + ';' +
'insert into changes ' +
'values(' + id + ',' +
'"system",' +
'"ticket expired",' +
'"' + (today.getUTCMonth() + 1) +
'/' + today.getUTCDate() +
'/' + today.getUTCFullYear() +
'");',
function(err) {
if (err) {
console.log(err);
return;
}
console.log(id);
sendAlert(id);
}
);
})(rows[i].ticket_id);
}
}
As you can see I tried to use an anonymous function to keep the data in each call from changing but it still didn't work.
I don't know if I am missing something.
Seems the execution of this task is asynchronous. When you need to iterate over asynchronous calls, the operation sequence is not guaranteed.
Maybe you need some control flow library such Async or Promise. There has some methods to control these flows even in iterations.

Javascript weird if else not working [duplicate]

This question already has answers here:
Javascript string/integer comparisons
(9 answers)
Closed 6 years ago.
Anyone knows why showToast always pops up even if desiredquantity is greater than inventoryCount?
function checkavailable(){
var desiredquantity = document.getElementById("bin-Qty").value;
var inventoryCount = document.getElementById("bin-binItem-quantity").value;
var itemName = document.getElementById("bin-binItem").value;
if(desiredquantity > inventoryCount)
{
console.log(desiredquantity);
showToast('There are only ' +inventoryCount +' '+itemName+' left');
}
else
{
addToTransfer();
}
}
I have a button to that calls checkavailable
<button type="button"
onclick ="checkavailable();">
</button>
Please convert it to number first
Like this
if (+desiredquantity > +inventoryCount) { // + will parse it as number
console.log(desiredquantity);
showToast('There are only ' + inventoryCount + ' ' + itemName + ' left');
} else {
addToTransfer();
}
Or you can use parseInt if value is integer and if value float than use parseFloat
Like this
if (parseInt(desiredquantity) > parseInt(inventoryCount)) {
console.log(desiredquantity);
showToast('There are only ' + inventoryCount + ' ' + itemName + ' left');
} else {
addToTransfer();
}

JavaScript and extending 3rd party API

I'm updating my knowledge about JavaScript and I stuck on one lesson task.
I have API that is returning string...
API.workerName = function (worker) {
return worker.firstName + ' ' + worker.lastName;
};
The task is to prefix returning string and not change API, but extend it. I also have to avoid copying & pasting code, because 3rd party code can change. I should re-use it instead.
What I did is change this function after loading API...
API.workerName = function (worker) {
return '(' + worker.position + ') ' + worker.firstName + ' ' + worker.lastName;
};
... but I think I did it wrong.
To extend the method, you should save the old definition and call it from your extension:
API.oldWorkerName = API.workerName;
API.workerName = function(worker) {
return '(' + worker.position + ')' + API.oldWorkerName(worker);
};
Or maybe this is what your lesson is looking for:
API.workerPositionAndName = function(worker) {
return '(' + worker.position + ')' + API.workerName(worker);
};
Another neat way to save the old definition and also make it unavailable to anybody else, would be to do something like this using IIFE to create a closure:
API.workerName = (function() {
var old = API.workerName; // this old version is only available inside your new function
return function(worker) {
return '(' + worker.position + ')' + old(worker);
}
})();
Here's an example:
API = {
workerName: function (worker) {
return worker.firstName + ' ' + worker.lastName;
}
};
API.workerName = (function () {
var old = API.workerName;
return function (worker) {
return '(' + worker.position + ')' + old(worker);
};
})();
alert(API.workerName({firstName: "Joe", lastName: "Blogs", position: "Lackey" }));

How to avoid timeout while reading rows from a query (Phonegap + Javascript)

I am trying to insert around 58000 rows of a query inside a string. But after the row around 8000 I get a timeout error.
I've already tried to use SetTimeout funcions but it was of no use.
Check the code that I am working on:
function onQuerySuccess(tx, results) {
console.log("Entering onQuerySuccess");
if(results.rows) {
console.log("Rows: " + results.rows.length);
var len = results.rows.length;
if(len > 0) {
store_html(results, 0);
console.log("Finished Reading Rows: " + len);
saveNotes();
console.log("Finished Saving Notes");
} else {
//This should never happen
console.log("No rows.");
}
} else {
alert("No records match selection criteria.");
}
console.log("Leaving openView");
function store_html(results, rows_complete){
rows_complete=store_html_input(results, rows_complete);
console.log("Returning row:" + rows_complete);
if (rows_complete<results.rows.length)
{
setTimeout(store_html(results, rows_complete), 50);
}
}
function store_html_input(results, rows_complete){
for(var i = rows_complete; i < rows_complete+100; i++) {
gpsTextFile = gpsTextFile + results.rows.item(i).section + ' ' + results.rows.item(i).timestamp + ' ' + results.rows.item(i).latitude + ' ' +
results.rows.item(i).longitude + ' ' + results.rows.item(i).acx + ' ' + results.rows.item(i).acy + ' ' +
results.rows.item(i).acz + ' ' + results.rows.item(i).speed;
gpsTextFile = gpsTextFile + "\n\r";
}
return i;
}
So.. I get that "Javascript execution exceeded timeout".
Thank you for any of your help!
Best Regards.
You need to change your setTimeout() to NOT execute the function immediately. Change from this:
setTimeout(store_html(results, rows_complete), 50);
to this:
setTimeout(function() {store_html(results, rows_complete)}, 50);
As you had it before, it was immediately executing store_html(results, rows_complete) and passing the return value from that to `setTimeout() which was not delaying anything. This is a common mistake (2nd one of these problems I've answered today).

Pass additional parameter to Javascript callback function [duplicate]

This question already has answers here:
Pass an extra argument to a callback function
(5 answers)
Closed 6 years ago.
I need to watch a small number of directories in a Node.JS application:
function updated(event, filename){
log("CHANGED\t/share/channels/" + filename);
}
for(i in channels)
fs.watch('share/channels/' + channels[i], {persistent: false}, updated);
The problem is that fs.watch only passes the filename to the callback function, without including the directory it's in. Is there a way I can somehow pass in an extra parameter to the updated() function so it knows where the file is?
I think I'm looking for something similar to Python's functools.partial, if that helps any.
Example using JS Bind
Doc: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
Tip, the bound parameters occur before the call-time parameters.
my_hello = 'Hello!'
my_world = {
'antartica': 'cold',
}
anonymous_callback = function (injected1, injected2, param1, param2) {
param1 = param1 ? param1 : 'One';
param2 = param2 ? param2 : 'Two';
console.log('param1: (' + typeof(param1) + ') ' + param1)
console.log('param2: (' + typeof(param2) + ') ' + param2)
console.log('injected1: (' + typeof(injected1) + ') ' + injected1)
console.log('injected2: (' + typeof(injected2) + ') ' + injected2)
console.log(injected2)
}.bind(this, my_hello, my_world)
anonymous_callback('Param 1', 'Param 2')
Output:
param1: (string) Param 1
param2: (string) Param 2
injected1: (string) Hello!
injected2: (object) [object Object]
{ antartica: 'cold' }
You can pass a different function for each iteration:
var getUpdatedFunction = function(folderName) {
return function(event, filename) {
log("CHANGED\t" + folderName + "/" + filename);
};
};
for(i in channels) {
foldername = 'share/channels/' + channels[i];
fs.watch(foldername, {persistent: false}, getUpdatedFunction(foldername));
}
You can use Function.bind:
function updated(extraInformation, event, filename) {
log("CHANGED\t/share/channels/" + extraInformation + filename);
}
for(i in channels)
fs.watch('share/channels/' + channels[i], {persistent: false},
updated.bind(null, 'wherever/it/is/'));
You can pass additional callback in place
function updated(channel, filename) {
log('CHANGED\t ' + channel + '/' + filename);
}
for(i in channels) {
channel = '/share/channels/' + channels[i];
fs.watch(channel, {persistent: false}, function (extra, event, filename) {
updated(channel, filename);
});
}

Categories