Reputation: 11
For my class, my professor wants us to create a simple node.js web site that reads a text file containing a fully qualified URL and then use the URL to retrieve JSON data from a remote web site and finally save the retrieved JSON to another text file. He wants the URL stored in a global variable.
I've done this, with a hardcoded URL, the one that's supposed to be read from the file. That runs fine and does what I want. My problem is when I try to create a global variable for the URL, it always returns undefined. I know it's a timing issue because the file is not being read asynchronously, but I can't figure out how to fix it.
'use strict';
// load the built-in http module
let http = require('http');
// load the add-in express module
let express = require("express");
// load the add-in xmlhttprequest and create XMLHttpRequest object
let XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
// create app object from express() constructor
let app = express();
// create a port number
let port = process.env.PORT || 3000;
let fs = require('fs');
// create a "get" event handler function
// request and response object references (req, res)
function getJSON() {
app.get("/", function (reqNode, resNode) {
var test = new Promise(function (resolve, reject) {
var req = new XMLHttpRequest();
req.open('GET', 'http://gd2.mlb.com/components/game/mlb/year_2017/month_07/day_08/master_scoreboard.json');
req.onload = function () {
if (req.status === 200) {
resolve(req.responseText);
}
else {
reject(req.statusText);
}
}
req.onerror = function () {
reject("network error");
};
req.send();
});
test.then(
function (response) {
// display in browser on success
resNode.send('JSON data saved to file.');
},
function (error) {
console.error("Request failed: ", error);
}
),
test.then(
function (response) {
// write the response to json.txt
fs.writeFile('json.txt', response, function (err) {
if (err) {
console.log(err);
}
else {
console.log('JSON data saved to file.');
}
});
},
function (error) {
console.log(error);
}
),
test.catch(
error => console.log(error)
)
});
}
(function () {
// create a server object
let server = http.createServer(app);
// listen on specified port for get requests
server.listen(port);
// call getJSON function
getJSON();
})();
This code works with a hardcoded URL, but I need a function to store it in a global variable instead.
Dependencies:
"dependencies": {
"express": "^4.17.1",
"xmlhttprequest": "^1.8.0"
}
And, the async/await that I tried. The 'url' variable returns as undefined, so this doesn't work. There are no errors returned, but localhost fails to load.
'use strict';
// load the built-in http module
let http = require('http');
// load the add-in express module
let express = require("express");
// load the add-in xmlhttprequest and create XMLHttpRequest object
let XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
// create app object from express() constructor
let app = express();
// create a port number
let port = process.env.PORT || 3000;
let fs = require('fs');
function readTxt() {
fs.readFile('urls.txt', { encoding: 'utf-8' }, function (err, data) {
if (err) {
console.log('Error reading file: ' + err)
}
else {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve(data);
}, 3000)
});
}
});
}
// create a "get" event handler function
// request and response object references (req, res)
async function getJSON() {
let url = await readTxt();
console.log(url);
app.get("/", function (reqNode, resNode) {
var test = new Promise(function (resolve, reject) {
var req = new XMLHttpRequest();
req.open('GET', url);
req.onload = function () {
if (req.status === 200) {
resolve(req.responseText);
}
else {
reject(req.statusText);
}
};
req.onerror = function () {
reject("network error");
};
req.send();
});
test.then(
function (response) {
// display in browser on success
resNode.send('JSON data saved to file.');
},
function (error) {
console.error("Request failed: ", error);
}
),
test.then(
function (response) {
// write the response to json.txt
fs.writeFile('json.txt', response, function (err) {
if (err) {
console.log(err);
}
else {
console.log('JSON data saved to file.');
}
});
},
function (error) {
console.log(error);
}
),
test.catch(
error => console.log(error)
)
});
}
(async function () {
// create a server object
let server = http.createServer(app);
// listen on specified port for get requests
server.listen(port);
// call getJSON function
getJSON();
})();
I don't believe this is a duplicate. I looked at other questions, I tried using async/await(code above), as answered to this question: https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call. That would likely work, but I'm having trouble getting it set up properly. Thanks in advance!
Upvotes: 1
Views: 1602
Reputation: 9116
Your implementation of readTxt
function is wrong. Here's the correct implementation of it. I have added comments to describe how to use promises.
function readTxt() {
// return a promise from the function
return new Promise(function (resolve, reject) {
// do the asynchronous operation
fs.readFile('urls.txt', { encoding: 'utf-8' }, function (err, data) {
if (err) {
console.log('Error reading file: ' + err)
// reject the promise in case of error
reject(err);
}
else {
setTimeout(function () {
// resolve the promise after successfull execution of asynchronous code
resolve(data);
}, 3000)
}
});
}
Upvotes: 1