Loading text from a file in JavaScript - javascript

I have created a function to get text from a file using an url. The function uses $.get() of jQuery to fetch the file. The function works fine but the problem here is $.get() is asynchronous so the order of the output is not predictable i tried changing it to synchronous but it freezes the page completely i have tried waiting for it to respond thinking i would take time but it didn't work.
Here's my code.
var File = (function () {
return {
GetTextFromFile:function(filePath) {
console.log ("Start")
$.get({
url:filePath,
async:true
}, function (data) {
console.log(data)
});
console.log ("End")
}
}
})();
This function outputs
Start
End
'Content_of_the_file'
This creates of problem because i cannot return the content of the file since it's not loaded yet because of the asynchronous get function. So is there any way to tell the function to wait till the $.get() has returned the content of the file.

Using async await we can make asynchronous to work in sync mode.
var File = (function () {
return {
GetTextFromFile: async function(filePath) {
console.log ("Start")
data = await $.get({
url:filePath,
async:true
}, function (data) {
return data
});
console.log(data)
console.log ("End")
return data
}
}
})();
await File.GetTextFromFile()

Related

Javascript Firebase RealTime Database Completion Block

I am trying to understand firebase-realtime-database. I am able to fetch the data, but I do not know how to add a completion block. I mean, is there a function to check when my data fetch query is completed?
function getData() {
firebase.database().ref('SectionNames').once('value', function(names) {
names.val().forEach(function(sectionname) {
firebase.database().ref('Sections').child(sectionname).once('value').then( function(child)
//code
});
});
});
//Completion block or a method to call processData() after I get all the sections
}
function processData() {
//call this function after you get all the sections
}
Thank you very much!
The once() method also returns a promise, so you can use the usual promise handling logic (then()/catch() or try/catch).
For example:
function getData() async {
let names = await firebase.database().ref('sections').once('value');
processData(names);
}
Update: since you now updated your code to show there are multiple once calls in a loop, you can use a Promise.all for that:
function getData() {
firebase.database().ref('SectionNames').once('value', function(names) {
let promises = [];
names.val().forEach(function(sectionname) {
promises.push(
firebase.database().ref('Sections').child(sectionname).once('value')
);
});
Promise.all(promises).then((snapshots) => {
processData(snapshots);
});
});
}

How to execute a Javascript function after another has completed using promises?

I wish to refresh the page after values have been saved to a database, using js promises.
My code is wrapped inside a jQuery event listener:
$("img[class=okButton]").click(function(){
var field_userid = $(this).attr("id");
doThisFirst();
// then make a promise
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
wait(500).then(() => writeNewRoom(field_userid)); // function to write to database
refreshPage(); // after write has finished
});
///////////////////
function writeNewRoom(field_userid)){
// ajax to do something;
}
///////////////////
function refreshPage(){
if(window.confirm("Click to refresh")){location = location}
}
The intended behaviour is to process data first, then finish "doing something" in the writeNewRoom() function before refreshing the page in the refreshPage() function.
What is actually happening is that the first doThisFirst() function is processed correctly, but then the window.confirm box in the third function, pops up BEFORE the writeNewRoom function has run.
I've never used promises before, so can anyone help figure out what went wrong? I took the basic syntax from the mozilla website: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises
Any help is much appreciated.
In your case, you would want to put a call back in your writeNewRoom() method.
For example, you call whatever you need to do on the .click() function and put a .done() method when your ajax call for writing to the database is done.
$("img[class=okButton]").click(function(){
var field_userid = $(this).attr("id");
doThisFirst();
// Remove the Promise
writeNewRoom(field_userid); // function to write to database
});
function writeNewRoom(field_userId) {
$.ajax({
url: "/someurl",
method: "method",
data: {
a: field_userId
}
}).done(function(data) {
console.log('success', data)
refreshPage(); // This is where you refresh the page.
}).fail(function(xhr) {
console.log('error', xhr);
});
}
If your // ajax to do something; returns a promise (jQuery.ajax() does) you can do it like this:
wait(500).then(() => writeNewRoom(field_userid))
.then(() => refreshPage());
There's also one extra parenthesis here function writeNewRoom(field_userid))
if the writeNewRoom(field_userid) is doing an ajax call, you put the refreshPage()-function into the callback of the ajax call, so it is executed AFTER the ajax has finished, e.g:
function writeNewRoom(field_userid)){
$.ajax({
url: "someUrl",
type: 'GET',
success: (result) => {
refreshPage() //when ajax has succeded, refresh page
},
error: (err) => {
//do something else
}
});
}

How to delay the inline javascript loading time?

In my usecase, I am using both external and inline javascript contents. I have the following structure.
app/
header.html
home.html
config-load.js
footer.html
home.html includes header.html and footer.html. header.html file includes config-load.js.
config-load.js makes an ajax call to get the configs based on the stage from golang backend. This may have few milliseconds delay.
There are few inline scripts in home.html which uses the configs collected by config-load.js ajax call.
So config-load.js ajax call must be completed before inline scripts are loaded. But it is loading in the other way around.
I tried to use a while loop to delay the load time for the inline scripts as below,
while(configReceived == false)
{
setTimeout(function(){
console.log("waiting for config");
}, 2000);
}
if(configReceived)
{
//process configs
}
But this blocks the thread. The page is stuck in the while loop. Is there any other way to achieve this?
EDIT 1 :
Here is the inline script content,
<script type="text/javascript">
window.onload = function() {
time = new Date($.now());
var tagsArray = ["C", "C++", "Go", "Ruby"];
//var tagsArray = [];
requestJSON = '{"Method":"GET","AppName":"Web-app","ServiceURL":"'+endpoints.Tags.HTTPEndpoint.URL+'","Properties":null,"Object":"","Timestamp":"'+time+'"}'
$.ajax({
type: "GET",
url: endpoints.Tags.HTTPEndpoint.URL,
data: requestJSON,
processData: false,
contentType: "application/json;",
dataType: "json",
async: false,
success: function(data){
console.log("tags retrieved successfully info updated successfully")
console.log("Tags ", data.Object)
tagsArray = data.Object
},
failure: function(errMsg) {
console.log("Error occured in getting tags ", errMsg)
}
});
$("#myTags").tagit();
$("#tags").tagit({
fieldName: "tagsName", // The name of the hidden input field
availableTags: tagsArray,
allowSpaces:true,
caseSensitive:false,
removeConfirmation:true,
placeholderText:"Tags",
tagLimit: 5,
allowDuplicates: false,
singleField: true, // Use a hidden input element with the fieldName name
singleFieldDelimiter: ',', // Optional, default value is same.
onlyAvailableTags: false
});
}
</script>
And my config-load.js looks like below,
//////////////////////////////////////////////////////////
// code block to get the service endpoints by stage starts
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
endpoints = JSON.parse(xhr.responseText);
console.log("server endpoints be ", endpoints);
configReceived = true;
}
}
xhr.open("GET", "/config", true);
try {
xhr.send();
} catch (err) {
// handle error
console.log("Error occured in getting the service endpoints. This may break all ajax services");
}
// code block to get the service endpoints by stage ends
////////////////////////////////////////////////////////
I am trying for last 3 days but no luck.
"while loop" is synchronous, which means it will block the thread and makes whole application stuck.
Javascript async scripts's execution order is not guaranteed, so you should use the "callback" or in ES6 you can use promise, ES7 you can use async, await.
Anyway the better way is wrap your config-load.js javascript code in a function, if you use Jquery's ajax api, the code may looks like this:
function loadConfigAjax(callback){
$.ajax({url: "http://myconfig", success: function(config){
callback(config)
}});
}
And in your inline javascript may looks like this
<script type="text/javascript">
window.onload = function() {
var configReceived = function(config){
//process configs
};
// pass the configReceived as callback
// so that configReceived function will always be invoked after config received
loadConfigAjax(configReceived);
}
</script>
Be aware that javascript is asynchronous and you don't have full control over the loading sequences of the scripts, unless you are not using the async await new javascript feature or promises. But in your case is not really needed for these.
First thing you need to do is to include the config-load.js in the head section, right on the top, this way you have some guarantee that the file is loaded before the DOM is getting populated.
Another thing is to use the window.onload function inside the inline scripts, to force the browser to parse the scripts only after all the DOM structure has been constructed and fully populated.
So inside your html section wrap your function into the window.onload function callback:
<script type="text/javascript">
window.onload = function() {
while(configReceived == false)
{
setTimeout(function(){
console.log("waiting for config");
}, 2000);
}
if(configReceived)
{
//process configs
}
}
</script>
EDIT:
There are quite a few errors in your approach. First and foremost there is no need to call the ajax requests in two separate scripts. Using the above mentioned promise technique you can chain the responses. Here is a short example of how the jquery promises are working:
function first() {
return $.ajax(...);
}
function second(data, textStatus, jqXHR) {
return $.ajax(...);
}
function third(data, textStatus, jqXHR) {
return $.ajax(...);
}
function main() {
first().then(second).then(third);
}
Remember: a call in the chain group return the response. Which means that you can delegate the response to the next chain, which means that when the request has been resolved you can pass through the result to the next call.
Applying to your example when you receive the response by calling the endpoints service, you can pass the result as parameter to the next call, and this will be accessed only when the response from the first call will be resolved.
Check this fiddle as an example.
Applying this technique it's not needed needed anymore to check configReceived = true;.
Another thing you have to make sure is that jQuery is included before you are trying to call jQuery.ajax.
Here are some references about promises:
http://www.danieldemmel.me/blog/2013/03/22/an-introduction-to-jquery-deferred-slash-promise/
http://www.bitstorm.org/weblog/2012-1/Deferred_and_promise_in_jQuery.html
https://davidwalsh.name/write-javascript-promises

How to wait for getJSON to finish in a Mocha test?

The below files are within a project created with the generator-webapp generator for Yeoman. My script is working in the browser and returns the information from the JSON file but does not work in the test most of the time. The test succeeds sometimes which means the test hits a hiccup long enough to allow the getJSON to return the data in time. In my search, I found various resources, here are two sources that sounded like they should be solving my issue: a stackoverflow question and a blog.
They both involve passing the done parameter to the it function and then calling done(); after executing the test. At least, that is my understanding but it still isn't working. I feel I am missing something really obvious.
Here is app/scripts/source-data.js.
var source = (function() {
var sourceData = null;
_loadData();
function _loadData(done) {
$.getJSON("app/data/source.json", function(data) {
sourceData = data;
});
}
function getData() {
return sourceData;
}
return {
getData: getData
};
})();
Here is test/spec/source-data.js.
(function() {
describe("Source Data", function() {
describe("Data for External Modules", function() {
it("returns the source data from a file", function(done){
expect(source.getData().spec[0].name).to.equal("Spec");
done();
});
});
});
})();
I tried altering where done() is called as my understanding was that done() tells Mocha to go ahead with the rest of the test after the getJSON is done. However, at this point, this was just trial and error as I found I had no real understanding.
...
var data = source.getData();
done();
expect(data.spec[0].name).to.equal("Spec");
...
Following the above, I tried setTimeout in the main script but that still didn't work! Even if it did, I don't think I should use setTimeout in this situation, but properly wait for the resolution of getJSON.
You should use callback.
For example:
var source = (function() {
var sourceData;
function getData(done) {
if(sourceData){
done(sourceData);
} else {
$.getJSON("app/data/source.json", function(data) {
sourceData = data;
done(data);
});
}
}
return {
getData: getData
};
})();
and test will be like this
(function() {
describe("Source Data", function() {
describe("Data for External Modules", function() {
it("returns the source data from a file", function(done){
source.getData(function(sourceData){
expect(sourceData.spec[0].name).to.equal("Spec");
done();
});
});
});
});
})();

How to use jQuery ajax data to variable

I have the following javascript code:
function initSite(){
var site;
$.getJSON(www+'init/initSite', function(data) { site = data; });
}
$(document).ready(function(){
var site = initSite();
console.log(site);
}
which returns undefined... how can i store the json object that i recieve in the site variable so i can use it later?
EDIT:
This seem to work but im not sure if its correct to use this solution
var site = null;
$.ajax({
url: www+"init/initSite",
async: false,
dataType: 'json',
success: function (data) {
site = data;
}
});
console.log(site);
of course you got undefined because your function doesn't return anything and the ajax call is also asynchronous, so you have to wait the server response. Since $.ajax (and shortcuts) returns a promise you can do this task using deferred
function initSite(){
return $.getJSON(www+'init/initSite');
}
$(document).ready(function(){
$.when(initSite()).done(function(data) {
/* continue here the code execution, e.g. call another function */
doAllTheRemainingWorkWith(data)
});
}
as you can see this code is short and easy to read
function initSite(onSuccess){
$.getJSON(www+'init/initSite', onSuccess);
}
$(document).ready(function(){
initSite(function(data){
var site = data;
// initialize your code.
});
}
The problem is just a miss concept:
getJSON is an async call, and the site = data; will only happen way after the DOM is ready.
in order for you to make everything work the way it should, your initialization needs to start from your async call result and never before, for example:
// no need to wait for DOM ready to call `initSite`
initSite();
function initSite() {
$.getJSON(www+'init/initSite', function(data) {
initialization(data);
});
}
function initialization(site) {
// initialize all the things that need to be done
console.log(site);
}
$(document).ready(function(){
// do other stuff, for example show a loading message/image
}

Categories