Node isDirectory() not working properly or i am missing somenthing - file

I want to get all names of files and directories from path and recognize them as files and directories. but When i run my code sometimes it works and somentimes it shows that directories are files. Here is the code
socket.on('data',function(path){
fs.readdir('path',function(err, data) {
var filestatus=[];
var z=0;
var i=data.length-1;
data.forEach(function(file){
fs.stat(file, function(err, stats) {
filestatus[z]=stats.isDirectory()
if (z==i){
socket.emit('backinfo',{names:data,status:filestatus});
}
z++;
})
})
})
})
During tests i realized that when i slow down data.forEach loop (using console.log(something) it works better(less miss). And this is strange.

This is about 96% incorrect, thank you to JohnnyHK for pointing out my mistake, see the comments below for the real problem / solution.
Because the fs.stat() function call is asynchronous, the operations on the filestatus array are overlapping. You should either use the async library as elmigranto suggested, or switch to using fs.statSync.
More details on what's happening:
When you call fs.stat(), it basically runs in the background and then immediately goes onto the next line of code. When it has got the details of the file, it then calls the callback function, which in your code is the function where you add the information to the filestatus array.
Because fs.stat() doesn't wait before returning, your program is going through the data array very quickly, and mutliple callbacks are being run simultanously and causing issues because the z variable isn't being incremented straight away, so
filestatus[z]=stats.isDirectory()
could be executed multiple times by different callbacks before z gets incremented.
Hope that makes sense!

you are using for statement in NODEJS and this will work if turned the For Statement to recursive function please see the attached code for help
function load_Files(pat,callback) {
console.log("Searching Path is: "+ph);
fs.readdir(pat,(err,files)=>
{
if(err)
{
callback(err);
}
else
{
var onlydir=[];
var onlyfiles=[];
var d=(index)=>
{
if (index==files.length)
{
console.log("last index: "+ index);
var ar=[];
ar.concat(onlydir,onlyfiles);
callback(null,ar);
return;
}
fs.stat(files[index],(err,status)=>
{
console.log("the needed file " +files[index]);
if (status.isDirectory())
{
onlydir.push(files[index]);
}
else
{
onlyfiles.push(files[index]);
}
console.log("only Directory: "+onlydir.length);
console.log("index: "+ index);
d(index+1);
}
)
}
d(0);
}
});
}

Related

modifying object in componentDidMount() [duplicate]

I’ll start with the code:
var s = ["hi"];
console.log(s);
s[0] = "bye";
console.log(s);
Simple, right? In response to this, the Firefox console says:
[ "hi" ]
[ "bye" ]
Wonderful, but Chrome’s JavaScript console (7.0.517.41 beta) says:
[ "bye" ]
[ "bye" ]
Have I done something wrong, or is Chrome’s JavaScript console being exceptionally lazy about evaluating my array?
Thanks for the comment, tec. I was able to find an existing unconfirmed Webkit bug that explains this issue: https://bugs.webkit.org/show_bug.cgi?id=35801 (EDIT: now fixed!)
There appears to be some debate regarding just how much of a bug it is and whether it's fixable. It does seem like bad behavior to me. It was especially troubling to me because, in Chrome at least, it occurs when the code resides in scripts that are executed immediately (before the page is loaded), even when the console is open, whenever the page is refreshed. Calling console.log when the console is not yet active only results in a reference to the object being queued, not the output the console will contain. Therefore, the array (or any object), will not be evaluated until the console is ready. It really is a case of lazy evaluation.
However, there is a simple way to avoid this in your code:
var s = ["hi"];
console.log(s.toString());
s[0] = "bye";
console.log(s.toString());
By calling toString, you create a representation in memory that will not be altered by following statements, which the console will read when it is ready. The console output is slightly different from passing the object directly, but it seems acceptable:
hi
bye
From Eric's explanation, it is due to console.log() being queued up, and it prints a later value of the array (or object).
There can be 5 solutions:
1. arr.toString() // not well for [1,[2,3]] as it shows 1,2,3
2. arr.join() // same as above
3. arr.slice(0) // a new array is created, but if arr is [1, 2, arr2, 3]
// and arr2 changes, then later value might be shown
4. arr.concat() // a new array is created, but same issue as slice(0)
5. JSON.stringify(arr) // works well as it takes a snapshot of the whole array
// or object, and the format shows the exact structure
You can clone an array with Array#slice:
console.log(s); // ["bye"], i.e. incorrect
console.log(s.slice()); // ["hi"], i.e. correct
A function that you can use instead of console.log that doesn't have this problem is as follows:
console.logShallowCopy = function () {
function slicedIfArray(arg) {
return Array.isArray(arg) ? arg.slice() : arg;
}
var argsSnapshot = Array.prototype.map.call(arguments, slicedIfArray);
return console.log.apply(console, argsSnapshot);
};
For the case of objects, unfortunately, the best method appears to be to debug first with a non-WebKit browser, or to write a complicated function to clone. If you are only working with simple objects, where order of keys doesn't matter and there are no functions, you could always do:
console.logSanitizedCopy = function () {
var args = Array.prototype.slice.call(arguments);
var sanitizedArgs = JSON.parse(JSON.stringify(args));
return console.log.apply(console, sanitizedArgs);
};
All of these methods are obviously very slow, so even more so than with normal console.logs, you have to strip them off after you're done debugging.
This has been patched in Webkit, however when using the React framework this happens for me in some circumstances, if you have such problems just use as others suggest:
console.log(JSON.stringify(the_array));
Looks like Chrome is replacing in its "pre compile" phase any instance of "s" with pointer to the actual array.
One way around is by cloning the array, logging fresh copy instead:
var s = ["hi"];
console.log(CloneArray(s));
s[0] = "bye";
console.log(CloneArray(s));
function CloneArray(array)
{
var clone = new Array();
for (var i = 0; i < array.length; i++)
clone[clone.length] = array[i];
return clone;
}
the shortest solution so far is to use array or object spread syntax to get a clone of values to be preserved as in time of logging, ie:
console.log({...myObject});
console.log([...myArray]);
however be warned as it does a shallow copy, so any deep nested non-primitive values will not be cloned and thus shown in their modified state in the console
This is already answered, but I'll drop my answer anyway. I implemented a simple console wrapper which doesn't suffer from this issue. Requires jQuery.
It implements only log, warn and error methods, you will have to add some more in order for it to be interchangeable with a regular console.
var fixedConsole;
(function($) {
var _freezeOne = function(arg) {
if (typeof arg === 'object') {
return $.extend(true, {}, arg);
} else {
return arg;
}
};
var _freezeAll = function(args) {
var frozen = [];
for (var i=0; i<args.length; i++) {
frozen.push(_freezeOne(args[i]));
}
return frozen;
};
fixedConsole = {
log: function() { console.log.apply(console, _freezeAll(arguments)); },
warn: function() { console.warn.apply(console, _freezeAll(arguments)); },
error: function() { console.error.apply(console, _freezeAll(arguments)); }
};
})(jQuery);

"expect" to continue test even after failing

I'm still a beginner in Protractor so forgive me if it is not the most optimized code. Although any advice and help are appreciated.
var orderno =["100788743","100788148","100788087","100000000","100786703"];
for (var i = 0; i < orderno.length; i++) {
(function(Loop) {
element(by.css('[autoid="_is_3"]')).sendKeys(orderno[i]);
browser.actions().sendKeys(protractor.Key.ENTER).perform();
expect(element(by.cssContainingText("span.Class", "Store A")).waitReady()).toBeTruthy();
element(by.cssContainingText("span.Class", "Store A")).isDisplayed().then(function(pickfail) {
if (pickfail) {
element(by.css('[class="highlight"]')).getText().then(function(text) {
console.log(text + "-" + "Pass");
});
} else {
console.log("Order Number: Missing");
}
});
element(by.css('[autoid="_is_3"]')).clear();
})([i]);
};
*waitReady is there to wait for the element to come up but I believe it its trying to find it but couldn't so it timesout.
I've created a test where I could input a value in a textbox which would search and check if it exists or not. If it does, it passes but if it doesn't, then fails. But want the loop to continue even if it fails to see if the other remaining items exist.
I think expect would fail when it couldn't find the value thus stopping the whole test. Is there another way to check and continue the whole checking?

Chrome extension won't enter for..of loop despite array length equal to 1

Background
Developing a Chrome extension (latest Chrome running on Mac OS Sierra) and I can't work out how to loop over an array which is also dynamically built at runtime.
Forgive me if I am missing something really obvious, but I cannot for the life of me work out why this for..of loop is not being entered.
I've also tried a for..in and the good old classic for loop structure i.e. for (let i = 0; i < array.length; i++) - no matter what style of loop this block is never entered, despite my array at runtime reportedly having a single item in it.
Problem Code and Statement
This code gets all files inside a directory and slices off the last 3 chars (to remove .js):
const getDirectoryContents = (path) => {
let fileNames = []
chrome.runtime.getPackageDirectoryEntry( (directoryEntry) => {
directoryEntry.getDirectory(path, {}, (subDirectoryEntry) => {
const subDirectoryReader = subDirectoryEntry.createReader()
subDirectoryReader.readEntries( (entries) => {
for (const entry of entries) {
fileNames.push(entry.name.slice(0, -3))
}
})
})
})
return fileNames
}
From inside the chrome.runtime.onStartup() callback function we want to add some context menus, which we do like so:
const addContextMenus = () => {
console.log(getDirectoryContents('commands'))
for (const command of getDirectoryContents('commands')) {
const properties = {
id: command,
title: command,
contexts: ['editable']
}
chrome.contextMenus.create(properties)
console.log(`Created context menu ${properties.title}`)
}
console.log('End addContextMenus')
}
Now, during runtime, the above code will output this inside the background page console:
However as we can see (due to the lack of the console logging "Created context menu ..." - the loop is never entered, despite the array having a length of 1.
I've found nothing online inside the Chrome developer docs that indicated that getDirectoryContents is asynchronous -- which would be one possible explanation -- but just to be sure I even tried adding a callback param to the getDirectoryContents function to ensure we are looping after the array has been populated.
EDIT: after closer inspection of the original function, it's clear that the array is in fact being returned before is has a chance to be populated by the directory reader. Answer below.
Same result!
Any help would be much appreciated. Thanks for your time.
How embarrassing! Passing in a callback function and executing it at the right time solved it. Comments were all correct - typical async issue - thanks for the support.
The problem was on line 15 of the original function: I was returning the array before it had a chance to be populated.
Working function:
const getDirectoryContents = (path, callback) => {
chrome.runtime.getPackageDirectoryEntry( (directoryEntry) => {
directoryEntry.getDirectory(path, {}, (subDirectoryEntry) => {
const subDirectoryReader = subDirectoryEntry.createReader()
let fileNames = []
subDirectoryReader.readEntries( (entries) => {
for (const entry of entries) {
fileNames.push(entry.name.slice(0, -3))
}
callback(fileNames)
})
})
})
}

Give an array to bluebird, call an API, then integrating the results into a single JSON output

Preamble
I had a thought: What if I reduced my duplicated data structures by stringing together my objects as microservices, and why don't I use Sails, nodejs and api calls. This is where it all started.
The problem definition
How can I send a dynamic array to a function, execute an unknown number of API calls to another microservice, then combine the returned values into a single object for processing?
The Journey
I have found material about q or bluebird.
I have a function (in sails) that returns me a list of users email addresses in a JSON array.
getUserInfo: function(opt, callback){
var https = require('https');
var options = {
hostname: opt.hostname || 'as.net.au',
port: opt.port || 443,
path: opt.path || '/developers',
method: opt.method || 'GET',
headers: opt.headers || {'Authorization': 'Basic ' + 'ThuperThecretKey'}
}
var req = https.request(options, function(res) {
var data = '';
res.setEncoding('utf8');
res.on('data', function(chunk) {
//console.log('BODY: ' + chunk); //oh so chunky
data += chunk;
});
res.on('end', function() {
//console.log(data)
callback(null, data)
})
})
req.on('error', function(e) {
console.log('problem with request: ' + e.message)
callback(e) //error
})
req.end()
}
It gives me back a set of email addresses in a JSON array:
['dev1#thisplace.com','dev2#thisplace.com','dev3#someotherplace.com']
and I stick this into a json object called "devs".
So now I want to pass this array to a function and have it execute an API call for every dev, and add the results into either the json object, or a new one. I assume a new one as devs is an array not a complete object.
The consensus from the Internet seems to be to use bluebird, but I am struggling with what I assume everyone struggles with, what variable is named what, which one gets updated, how to load things into the variable, where it goes, etc, etc, my head hurts. There are things going in entrances that I am not sure should be going there.
So I am asking for help. Does anyone have a example of the best way to do these asynchronously and then parse the results?
I got far enough to see a nice loop of asynchronous calls going out to my API (thats below), but how do I pass in and read a variable in the last then function?
It logged "Executing a promise for dev1#thisplace.com..... etc etc"
Then the "devs" object empty and the "dev" object as expected (each email address).
But how do I pass back to the calling json (or a new json) the output from My API call? How does it maintain and asynchronously update an object?
I assume something goes in the else after the error (Potential placeholder number 1).
Something like:
promise.map(devs, function(dev) {
console.log('executing a promise for ' + dev)
MyCont.getUserInfo({'path': '/developers' + dev}, function (err,devs) {
if (err) {
console.log(err)
} else {
console.log ('devs: ' + devs)
console.log('dev: ' + dev)
//Potential placeholder number 1 -Some here that loads the returned value to the passed in or new array?
}
})
}).then(function() {
//Or maybe it goes here?
console.log("done");
});
You touched on the first obvious solution, using Bluebird's map. First thing would be to use promises everywhere:
// make this a Promise
getUserInfo: function(opt) {
// your new best friend for issuing http requests without callbacks
var request = require('request-promise');
// the options have to change a little
var options = {
uri: 'https://'
+ opt.hostname || 'as.net.au' + ':'
+ opt.port || 443
+ opt.path || '/developers',
method: opt.method || 'GET',
headers: opt.headers || {'Authorization': 'Basic ' + 'ThuperThecretKey'}
}
// much shorter, right?
return request(options);
}
devs.map(function(dev) {
console.log('executing a promise for ' + dev)
return MyCont.getUserInfo({'path': '/developers' + dev});
}).then(function(results) {
// your results are here, in order
console.log(results);
});
I am going to assume, after reading all that, your question is this:
How can I resolve an existing promise using the results of a bunch of asynchronous functions calls?
First, start with the function inside your outermost promise:
var processEmailAddressList = function (addresses) {
// This is inside a promise.
// It will return when all addresses have been processed.
return Promise.map(addresses, processSingleAddress);
};
var processSingleAddress = function (address) {
// How you implement this is up to you -- and up to whatever
// promise library you are using. return a promise that resolves
// to the value you want
};
Here, we are using map, but we could use reduce. There are some extremely important performance characteristics between map and reduce (see below), but I will ignore that right now. All you need to know is that you are returning a promise that will resolve or reject when all of the items in addresses have been processed by the callback, processSingleAddress.
The question is how to write processSingleAddress.
If you can process that single address using in a way that already uses promises, then it is simple. Maybe you are using a library that is already Promise-ready. In this case, you just call that function directly.
var processSingleAddress = function (address) {
return addressProcessorWithPromise(address);
};
But if you cannot process your list items with promises, you need to figure out a way to do so using promises you create yourself. Here, for example, I am assuming that you are making an asynchronous call to getDataFromAsyncProcess() and that function takes a single address and a node-style callback.
var processSingleAddress = function (address) {
// input is `sample#example.com`
return new Promise(function (resolve, reject) {
getDataFromAsyncProcess(address, function (err, data) {
if (err) reject(err);
// example output is {address: 'sample#example.com', status: 'logged in'}
resolve(data);
});
});
};
At this point, you should expect things to run like this:
var addresses = ['sample1#example.com', 'sample2#example.com']
processEmailAddressList(addresses)
.then(function (list) {
// see below for the value of `list`
})
.catch(function (err) {
console.error(err);
});
Inside then, list should now look like this:
[
{address: 'sample1#example.com', status: 'logged in'},
{address: 'samples#example.com', status: 'logged in'},
]
I know this looks potentially confusing with the amount of indirection that appears to be going on (functions inside functions), but welcome to JS. And the more you get used to using promises, the easier it gets.
THe last thing to be really careful about is how map or reduce (or any other promise-library iterator) does things. If you have, 5 addresses and the process is not so expensive, this is not so critical, but if you have hundreds or thousands of things to process or the processor is expensive (database calls, network requests, memory consumption, etc.), you can end up chewing up a ton of memory and killing your database if all of those addresses are processed in parallel (all at once). If this is a factor, you should try to use an iterator that does things one at a time. Consult your library API for details.
Last note: please try to keep your questions simple. That was unnecessarily verbose.

Angular promises run conditionally

I'd like to perform an asynch function conditionally, but I think I'm missing the correct syntax to say what I want.
this.doUpToThreeThings = function(skipTheMiddleStep) {
return doFirstThing().then(function (result) {
if (skipTheMiddleStep) {
return doThirdThing();
} else {
return doSecondThing();
}
}).then(function (result) {
if (skipTheMiddleStep) {
return "ok"; // return what?
} else {
return doThirdThing();
}
});
}
By the time we get to the second then, I don't know if the first block did the middle step, so I'm forced into repeating the condition. And the second block reads weird: it should say, if skip the middle step, then do the third thing, but since it we know that the previous block must have done the third thing, it just returns. So I have to repeat the condition and write pretty wrong-looking code in the second then.
I realize I can write a function called doSecondAndThirdThings, and just call that from the condition in the first block, but that's not really DRY, it's just hiding the non-DRYness. (or maybe I'm wrong about that?)
Also, I'm still a little confused about returning a completed promise on that "ok" branch. Is that right how it is, or should I say something like resolve? -- Thanks
The deferred in thefourtheye's answer is pointless and is considered an anti pattern with promises.
Here is how I would do it:
this.doUpToThreeThings = function(skipTheMiddleStep) {
return doFirstThing().then(function (result) {
return (skipTheMiddleStep) ? doThirdThing() : doSecondThing().then(doThirdThing);
});
}

Resources