I am trying to make a simple read file function in my Appjs program. All that is happening is that the Appjs is calling a function inside my app.js file and running it in node.js. This function then returns a value to my Appjs program by window.returnData = data;
This works, however I can't get it to work in the order I want. The node.js function seems to be running AFTER the Appjs function although it is inside of it.
Here is the function inside of my Appjs index.html file that starts the entire process.
var returnData;
function r(path,d) {
window.readFromFile(path,d); //call to the function readFromFile below
alert(returnData);
}
readFromFile() function from the app.js file that Is being called from above
window.readFromFile = function(path,d) {
var fs = require('fs');
if (d == 1) {
path = __dirname + path;
}
fs.readFile(path, {encoding: 'utf-8'}, function(err,data){
if (err){
console.log(err);
} else {
console.log('File read');
window.returnData = data;
}
});
}
Here is my problem. The first call of this function will alert the text undefined. However, after the alert function, I know that the window.returnData = data; line above is working because if I create a button to alert the variable returnData again or I run the readFromFile function again, it alerts the data correctly.
Am I incorrect in thinking that the child function should complete first? Is there a way around this? I don't want to create a loop that continuously checks for the variable to change.
Thanks in advance.
Related
I have stubbed the content of file, so I can run through only outer function
file.html
<body onload ="test('file.txt')">
<body>
file.js
const fs1 = require('fs');
let param;
module.export = {
test,
test1,
param
}
function test (outputParam) {
let fileData = test1(outputParam);
param = fileData;
}
function test1(outputParam) {
let data = fs1.readFileSync(outputParam);
return data;
}
Here as you see I load function test from html onload and in turn test1 calls and reads file, I have stubbed this file content as shown in the test below
When I run the test I want to see the variable param has the file content value
test.spec.js
let sinon = require("sinon");
let filejs = require('./file.js');
it('should run only the outer function' ,function() {
// I try to stub my function here
sinon.stub(filejs,'test1').callsFake ((someArg) => {
return "this is my file content";
});
// Now I will call my test function
filejs.test(someArg);
})
As you seen above I have stubbed function test1, still when I run the test I see test1 gets called and it reads the real file.
I am using mocha , I am new to stub or mock concepts, any suggestion is really appreciated.
You should probably try to stub readFileSync.
const fs = require('fs');
// ...
sinon.stub(fs, "readFileSync").callsFake ((someArg) => {
return "this is my file content";
});
Besides that, I can spot two issues with your code.
The real readFileSync will return a Buffer if called without a second parameter, not a string like your stub does.
The body onload event only exists inside the DOM. The fs module is only available in Node.js. If you run your code in a browser, you won't be able to use fs.readFileSync. If you run it in Node, your HTML file and the onload event won't be useful.
I made a node web app and it works. However, I built it monolithic, and I'm attempting to break it out into modules for practice.
Long question short, in a module, how do I define a variable from callback results and store it in a way that it is available to the main app? is it as simple as storing the results in the module to a global variable and exporting that as well?
In my monolthic version:
app.js
var resultsArray = [];
function getDatafromHTTP(page){
callback(data){
resultsArray.push(data);//push json elements to array
if(page < 50){page++;getDatafromHTTP(page);}
}
}
getDatafromHTTP(0);
app.get(some function that displays the resultsArray)
The getDatafromHTTP function runs 50 times via the page variable.
Now that I tried to break it down:
app.js
var resultsArray =[];
var getDatafromHTTP = require(module.js).getDatafromHTTP
getDatafromHTTP(0);
app.get(some function that displays the resultsArray)
module.js
exports.getDatafromHTTP = function(page){
callback(data){
resultsArray.push(data);//push json elements to array
if(page < 50){page++;getDatafromHTTP(page);}
}
}
//error resultsArray not Defined.
I get why resultsArray is not defined in the module, and understand I can make resultsArray a variable in the module itself. If it was a return, i would simply define a variable in the main app based on the return of the function. But since the function gets data via a callback and not a return, whats the "right" way to get that data back into the main app and available for the app.get function? either as it builds, or after the 50 function runs completes?
There are a number of different ways to do this, but the most common pattern I've seen is to just add the value as a new property of app (or similar). So for example:
module.exports = function(app) {
return function getHttpData(callback) {
request.get('http://example.com/', (err, results, body) => {
if (err) return cb(err);
app.httpData = body;
return cb(null, body);
});
}
}
Then in your calling code you'd do something like:
var app = express();
var getHttpData = require('./get-http-data.js')(app); // <-- note I'm passing the app object in here
// sometime later
getHttpData((err, data) => {
console.log(data);
});
Obviously, I'm leaving off a few steps like some of the require statements and such, but hopefully you get the idea.
All that said, often you want to avoid global variables like that. In particular, storing things that potentially change like that in memory will lead to bugs later if your app has to scale to more than one process (each instance of the app would fetch separately, and possibly wind up with different states).
module.js
function getDataFromHTTP() {
return callback(data) {
return data;
}
}
module.exports = getDataFromHTTP;
app.js
var getDataFromHTTP = require('module.js');
var resultsArray = [];
for (var page=0; page<50; page++) {
resultsArray.push(getDataFromHTTP);
}
I am using nodejs and webdriver for automation tests. I am trying to export a function from one js file to another. e.g there is a function called abc under file abc.js and i want to use that function with other file called xyz.js. I tried using export and require but it exports and runs entire test (abc.js) instead of just a function.
//abc.js
console.log('print this');
client= function client() {
driver.get(baseUrl + '/#/login');
};
exports.client = client;
//xyz.js
var client1 = require('abc.js').client();
Requiring a module for the first time causes the module to be cached and it's code to be executed, that's why you're seeing your "print this" log. Next time you call your client function you shouldn't see it.
This is not relevant to the question, but still, in your xyz.js file, since your function isn't returning anything you can use:
require('abc.js').client();
Instead of:
var client1 = require('abc.js').client();
In your abc.js, there's no need for a named function, you can just use:
var client = function() {
...
};
give it a try
function abc(){
console.log('print this');
this.client= function client() {
driver.get(baseUrl + '/#/login');
};
return this;
}
module.exports = abc;
//xyz.js
var abc = require('abc.js')();
abc.client();
its a good practice when capsulating objects in nodejs
I want to execute 2 functions in a specific that I have imported from 2 other .js files that I have made. The function that needs to complete first takes a bit of time and the 2nd one starts before the first is ended and I need files the first one created for it to work. Here's basically what my .js looks like:
var pdfToPng = require("./pdfToPng.js");
var doStuffToPng = require("./doStufftoPng.js");
var pdfFilePath = process.argv[2];
var pngFilePath = pdftoPng.convert(PdfFilePath);//convert takes a path
//and makes a png and returns path
//to the png
doStuffToPng.doStuff(pngFilePath);
//I want "doStuff()" to start AFTER "convert()" is done.
Im pretty sure it has something to do with callbacks, but I'm a javascript noob and need help. I can get it to work with setTimeout(), but that seems like a "duct tape fix" to me. Is there some way more elegant?
Edit: some wonderful people wanted to help and asked to post this, the pdfToPng.js:
var spindrift= require('spindrift');//this is a node module
var fs = require('fs');
//Makes a png from pdf in pngFolder and returns the path to that png
exports.convert = function(path)
{
var pdf = spindrift(path);
var pathToPng = path.substring(0, path.length-4); //takes off the .pdf
pathToPng += "_out.png";
//this is spindrift's stuff, makes a png in dir pngFolder/pathToPng
pdf.pngStream(500).pipe(fs.createWriteStream("pngFolder/" + pathToPng));
return "pngFolder/" + pathToPng;
}
Welcome to the async world of javascript. The function callback though created synchronously is executed asynchronously. So you have to modify the code to get doStuff executed only after you know for sure that convert function has executed. You can find how this can be done # Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
if so, you need to implement your own callback,
- Open pdftoPNG.js
- modify convert function with one more parameter
function convert(PdfFilePath, finishConvert) {
//now just insert this line where you finally instead of return
//remove return yourpngpath; //or something, i assume
//add following in the place of return
finishConvert(yourpngpath);
}
Then Please call like this
var pdfToPng = require("./pdfToPng.js");
var doStuffToPng = require("./doStufftoPng.js");
var pdfFilePath = process.argv[2];
pdftoPng.convert(PdfFilePath,function(path){
if(path!="") {
doStuffToPng.doStuff(path);
}
});
You have to update your convert method to support callbacks/ promises.
Here is an example using Callbacks
exports.convert = function(path, fnCallback)
{
var pdf = spindrift(path);
var pathToPng = path.substring(0, path.length-4); //takes off the .pdf
pathToPng += "_out.png";
//this is spindrift's stuff, makes a png in dir pngFolder/pathToPng
pdf.pngStream(500).pipe(fs.createWriteStream("pngFolder/" + pathToPng));
if (fnCallback && typeof(fnCallback) === "function") {
fnCallback("pngFolder/" + pathToPng);
}
}
You'll see the following
A new parameter being passed in fnCallback
A check to make sure that the parameter is passed in and that it is a function
The fnCallback function gets called with the results passed in as a parameter
Removing of the return statement
Now when the convert method is called, after the long running process completes, the Callback method will get executed.
To call the modified convert method you now have to pass in a callback function
function myCallback(path){
// do something with the path
}
pdftoPng.convert(PdfFilePath,myCallback);
I'm currently trying to build an array of functions. I have a folder full of modules where each module has a function run and the following line
exports.run = run;
var run = function(db){
// Run some code
}
I then have a file I call in node which does the following:
require("fs").readdirSync("./channels").forEach(function(file) {
var func = require("./channels/" + file);
channels.push(func);
console.log("Adding " + file);
console.log(channels);
});
The function above successfully adds in each file with type undefined. I'm unable to run the functions because of this. How can I successfully build this array of functions?
The reason your code doesn't work as you expect it to, is variable hoisting in JavaScript.
var run = function(db){
// Run some code
}
exports.run = run;
If you don't want to push your exports line to the bottom of your function, then you'll have to declare run as a stand-alone function, rather than assigning it to a variable.
exports.run = run;
function run(db){
// Run some code
}