So I am new to Node development. My first personal project requires creating a local txt file of the html contents of a page for further manipulation. I don't know why everything else in the program is executed before the request call is made. For example in the below snippet, "Two" will always come before "One". I know it is probably something simple I am missing but I am hoping to learn something from it.
var request = require('request');
var fs = require('fs');
request('https://www.google.com', function (response, body) {
console.log("One")
fs.writeFile("ToParse.txt", body)
});
console.log("Two")
"Two" will always come before "One"
Because Node.js is asynchronous
What it does mean than previous function won't stop the execution process instead the functions are called irrespective of previous function has stopped execution
If you want a sequence use Callbacks or Promises
This is because of the async nature of nodejs/JavaScript because it's single Threaded, Request module is performing asynchronous operation and aftering completion or failure of the operation, it will call the last function which we call a callback function.
Request will take time to perform it's operation while doing a get method to www.google.com
Node will put that operation in queue and execute the other operation, in your case console.log it consoles the result and later from the queue it will execute the queued operation.
Visit this
https://developer.mozilla.org/en/docs/Web/JavaScript/EventLoop
The callback function first parameter should always be error, if no error occurs it will be null.
request('http://www.google.com', function (error, response, body) {
// your code
})
The function you passed as the second argument to the function request is a callback. It will be called once the request processed. The nature of Node.js is, to execute codes continuously without waiting(blocked) for the callback to be called. When the request completes(fails/succeeds) your callback will be called. That's why "Two" printed before "One"
Related
I run into an issue when trying to use the request method in javascript where I can't save a value. I'll run a block of code like:
let savedData;
request({
url: url,
json: true
}, function (err, resp, body) {
if (err) {
return;
}
savedData = body.data;
});
console.log(savedData);
I know that request doesn't block or something, so I think it's run after the console.log or something like that? I just need to know how I can save the desired data for use later in the method.
Your code is working correctly, you're just neglecting the fact that the callback provided as a second parameter to request() is executed asynchronously.
At the time when your console.log() is executed, the network request may or may not have successfully returned the value yet.
Further Explanation
Take a look at the documentation for the request() function.
It states that the function call takes the following signature,
request(options, callback);
In JavaScript, a callback performs exactly as the name perscribes; it calls back by executing the provided function, after it has done what it first needs to.
This asynchronous behavior is especially prominent in making networking requests, since you wouldn't want your program to freeze and wait for the network request to retrieve or send what you've requested.
Example
function callback() {
console.log('I finished doing my asynchronous stuff!');
console.log('Just calling you back as I promised.');
}
console.log('Running some asynchronous code!');
request({...options}, callback);
console.log('Hi! I'm being called since I'm the next line of code; and the callback will be called when its ready.');
Output
Running some asynchronous code!
Hi! I'm being called since I'm the next line of code; and the callback
will be called when its ready.
I finished doing my asynchronous stuff!
Just calling you back as I promised.
You'll either need to do the rest of the code in the callback of the request function, or use a promise. Anything outside of that callback is going to execute before saveedData ever shows up.
This question already has answers here:
How to identify if a callback is going to be executed synchronously or asynchronously? [duplicate]
(3 answers)
Closed 3 years ago.
Hi! I am learning about callbacks and I understand that callbacks can be either synchronous or asynchronous.
I was reading about callbacks on https://www.w3schools.com/jquery/jquery_callback.asp and was quite confused.
There is this code:
$("button").click(function(){
$("p").hide("slow", function(){
alert("The paragraph is now hidden");
});
});
Can I check if there is a way to know if the above callback is Synchronous or Asynchronous?
I am guessing it is Synchronous above because it has to wait till the "slow" animation is over before the alert comes up. Is it by default in Javascript or Node.js all callbacks are synchronous unless you do something like setTimeOut or process.nextTick?
You have several questions here, so I'll try to answer them one by one:
Is it by default in Javascript or Node.js all callbacks are synchronous unless you do something like setTimeOut or process.nextTick?
In the browser you can kinda have this as the rule of thumb: Only setTimeout, setInterval, requests and events are asynchronous. Other built-in callbacks (like Array.prototype.map) are synchronous.
On Node.js it's more complicated: e.g. you can do file reading both synchronously and asynchronously. Then you just need to know that the callback is asynchronous by nature.
Can I check if there is a way to know if the above callback is Synchronous or Asynchronous?
Unfotunately without checking the source code of the method/function you're calling you cannot know if it's synchronous or asynchronous.
I am guessing it is Synchronous above because it has to wait till the "slow" animation is over before the alert comes up.
Exactly. You can find this from jQuery's documentation for .hide method:
complete
Type: Function()
A function to call once the animation is complete, called once per matched element.
A callback is a function that will get executed once an Asynchronous process is completed. Let's say we have an object person with the following data.
var person = {
id: 1034
name: 'Julio',
age: 23,
moneyInBank: 0
}
We want to get the the moneyInBank for this person but we don't have access to that information in our local environment. We need to get it from a database in another server, this could take a while depending internet connection, optimization, etc.
getMoneyInBank(person.id, callback) is going to go over that process and fetch the information we need. If we were to run the next script without the callback.
getMoneyInBank(person.id);
console.log(person.money);
We will get 0 in the output because getMoneyInBank has not finished by the time the log is executed. If we want to make sure we will print meaningful information we need to change our code to something like this.
getMoneyInBank(persion.id, function(){
console.log(person.money);
});
Using a callback the log only is going to be called when getMoneyInBank finishes.
You can easily check:
function isSync(func, ...args){
var isSync = false;
const res = func(...args, r => isSync = true);
if(res instanceof Promise) res.then(r => isSync = true);
return isSync;
}
console.log( isSync([].map.bind([])) );
Short answer:
You need to examine the caller and look for async operations.
Long answer:
A callback is a simple pattern by which a function is passed as a parameter to an higher order function and is called back it or further down the stack.
let mySynchronousFunction = () => 'Hello';
let myHigherOrderFunction = aFunc => {
return (aFunc() || 'Goodbye') + ' world!';
};
As soon as there is an I/O operation that would block the main thread, it instead will "branch out" and continue execution.
If we continue with our previous example, we would observe the following behavior:
let myAsyncFunction = () => {
return http.get('http://some.document')
.then(response => console.log(response)
);
};
myHigherOrderFunction(mySynchronousFunction); // 'Hello world!'
myHigherOrderFunction(myAsyncFunction); // 'Goodbye world!'
What happened here is that the main thread continued all the way until it had to wait for I/O and instead of blocking there, it went to the next instruction and took note of the point at which it needs to go when the I/O operation is no longer blocked.
So the next expression to evaluation in our code is:
return expression
But our expression branched out, as such it returns undefined. So we are left with:
return undefined
This means that our higher order function that was passed an async function got undefined when it called aFunc().
Once the I/O is done, the main thread returns to where it left off which is the function passed to Promise handler then. At this point the execution thread has branched out and is separated from main "thread".
Now for your question
The callback will be synchronous when the higher order function which calls it is calling it synchronously. Inversely if it is called within the context of the execution branch of an asynchronous operation it will be asynchronous.
This mean that you need to examine what the higher order function to which you pass your callback is doing and look for async operations.
In the context of your question let us examine the following code (HOF = Higher order function):
let mySynchronousHOC = aFunc => aFunc('Hello world!');
let myAsyncHOC = aFunc => {
http.get('http://hello.com')
.then(response => aFunc('Goodbye world!')
);
};
myAsyncHOC(msg => {
console.log(msg);
});
mySynchronousHOC(msg => {
console.log(msg);
});
The result of which will be:
'Hello world'
'Goodbye world'
Here we know that myAsyncHOC is asynchronous because it does an I/O operation.
I am not sure "synchronous" and "asynchronous" makes sense in this context. You can talk about sync or async when making ajax requests, which would mean that in a sync request everything else stops until the response is received, while in an asynchronous request something else can happen until the server sends the response.
In your particular case ( https://www.w3schools.com/jquery/jquery_callback.asp ) what happens is this:
in the "slow" case a timeout is set and the callback is called when the time is out
in the second case a timeout is set for hiding the paragraph but the function is called imediately on the next line, before the time is out
this is not sync/async, it is about event programming
When run, the code shown below logs "[]". I believe this is because the request function is not complete by the time the console.log method is called.
var urlArray = []
request('http://www.example.com', function (error, response, body) {
urlArray.push("example.com")
}
console.log(urlArray)
How do i put a conditional to make sure the request function is complete. the pseudo code would be:
if request function is complete{
console.log(urlArray)
}
If this isn't the best way, what is?
First, if you run it non-async, the line right after the request line will be executed when the request finishes, but thats not recommendable. Second, running async, ussually you get a callback or a promise depending the library you are using in order to perform the request, even if you use pure JS, you have the option to set callbacks for error and success states, that will be executed only after the request has received a response.
I recommend reading a bit about ajax and promises.
http://www.w3schools.com/ajax/ajax_xmlhttprequest_send.asp
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then
Having a look at the code you've provided, it seems that is just a concept or pseudocode, that will never run and throw all kind of errors and exceptions.
I can't seem to reconcile the technical flow of javascript execution sequence and the concept of callbacks. I have been using callbacks, but I am uneased of the execution flow because it appears that there are contradictions between idea of callback and the sequential javascript execution. This link http://cwbuecheler.com/web/tutorials/2013/javascript-callbacks/ explains callback and give examples, but I as I follow the code, I see a contradiction.
getData('http://fakedomain1234.com/userlist', writeData);
document.getElementById('output').innerHTML += "show this before data ...";
function getData(dataURI, callback) {
var myData = getSomeData(); // fake function
callback(myData);
}
function writeData(myData) {
document.getElementById('output').innerHTML += myData;
}
my question/observation is that inside the function getData, the callback(myData) statement does not get executed until after the function getSomeData() is finished and returned a value to the variable myData, but then the contradiction occurs when the document.getElementById... statement is allowed to execute before the getData function call is finished executing.
Am I missing something?
TIA
Synchronous vs. Asynchronous Execution
I think you're getting those two things mixed up. I'll quote and correct you below:
the callback(myData) statement does not get executed until after the function getSomeData()
Correct. This is synchronous (line-by-line) execution.
the document.getElementById... statement is allowed to execute before the getData function call is finished executing.
Incorrect. Again, this is synchronous execution - 'show this before...' will be inserted after the data.
You're likely thinking about callbacks in the context of asynchronous execution. Compare your synchronous code to this asynchronous version, which does insert 'show this ...' before the contents of myData:
getData('http://fakedomain1234.com/userlist', writeData);
document.getElementById('output').innerHTML += "show this before data ...";
function getData(dataURI, callback) {
//var myData = getSomeData();
//callback(myData);
getSomeDataAsync(callback);
}
function writeData(myData) {
document.getElementById('output').innerHTML += myData;
}
The change is in the getData function. callback is passed as an argument, rather than called immediately with the () operator.
The getSomeDataAsync function is asynchronous, meaning it will pop itself in the run loop's "background" before executing your myData callback. It won't run your callback until the event it is waiting for fires (i.e. when data retrieval completes). While getSomeDataAsync is waiting, execution resumes on the code that called it, which will insert your 'show this before...' immediately.
When the completion event fires, execution will resume, and the passed callback parameter will be executed. The contents of myData will then be appended!
Check out this fiddle to see what I mean
document.getElementById cannot be executed before getData gets completely executed, unless getData is asynchronous. By seeing there's a URL passing to getData tells me you are doing AJAX which is asynchronous.
Although your code won't behave like you said (it's synchronous!) because var myData = getSomeData() is synchronous, pretending the whole getData function is async and the flow goes like this:
Executes getData.
getData does its internal stuff and returns undefined.
Proceeds to document.getElementById.
Later getData gets its data and the browser or other environment executes the callback function passed to it before.
Executes statements inside writeData.
There are many ways that can create an async function, such as events, AJAX, and other timers (setTimeout/Interval).
I can't seem to grasp the concept of a callback. I haven't worked with them before so bear with me. To get my hands wet, I'm trying to login to twitter with zombie.js.
Here is an example:
var Browser = require("zombie");
var browser = new Browser({ debug: true})
browser.visit("https://mobile.twitter.com/session/new", function (callback) {
browser.fill("username", "xxxxx");
browser.fill("password", "xxxxx");
browser.pressButton("Sign in", function (err, success) {
if(err){
console.log(browser.text('.message'));
console.log('There has been a error: ' + err);
}
else{
console.log('Worked!');
}
});
});
At the browser.pressButton part, it will determine if I have been able to successfully login or not, depending on if .message contains the text "Typing on your phone stinks, we know! Double-check your username and password and try again."
However, I don't understand how it determines to fire the callback err. If .message isn't present in the html, then I would like to trigger the success callback to move onto the next function.
The convention Zombie seems to use for callbacks comes from node.js where the first argument is an error object, which should be null on success, and any subsequent arguments are for the success case. If you define a callback, the library you are using (Zombie in this case) will execute your callback function when their async operation is complete. When your callback is invoked it means "OK, an operation has completed and you can now process the result as you see fit". Your code needs to look at that first argument to decide if the operation was a success or failure.
When you accept a callback function as an argument and then perform some (possibly asynchronous) operation, the callback is the way for you to tell the calling library you are done, and again use that first argument to distinguish errors from success.
Part of your confusion is probably coming from the fact that your function signature for the callback to browser.visit is wrong. You need to name that first argument to clearly indicate it's an error like this:
browser.visit("https://mobile.twitter.com/session/new", function (error, browser) {
So in the body of that anonymous callback function, if zombie couldn't load that page, the error argument will have info about the error. If the page did load correctly, error will be null and the browser 2nd argument can be used to further tell zombie to do more stuff on the page. This is how Zombie says "I'm done with the visit operation, time for you to handle the results."
visit doesn't pass a callback argument, the anonymous function you pass as an argument to visit IS THE CALLBACK. You could code it like this to clarify (although nobody does)
browser.visit("https://mobile.twitter.com/session/new", function callback(error, browser) {
So that's a callback when a library needs to tell you it is done. You don't invoke it. The library invokes it and you put code inside it.
On the other hand, when your code does async operations, you need to invoke the callback that you received as a function argument appropriately to tell your caller that you are done and whether it was success for failure. In this case, you don't do any of your own async code, so there's no need for you to invoke any callback functions.