Lecture_14_Transcript
Lecture_14_Transcript
We are going to step back and look at several different ways that Async requests can be handled in
JavaScript.
While the JavaScript engine itself is “single-threaded” the “Browser” is multithreaded and thus can
offload a potentially long running call, e.g. an HTTP request, to a different thread – one other than the
“web-ui” is running on. To be able to process the results of the long running call, when we call the
Aysnc function we also provide, as a parameter in the call, a function which will be invoked / “called
back” upon completion of the asynchronous task. When the Browser event loop receives an indication
that the asynchronous task is complete it invokes the “call back.”
One of the ‘programming patterns” that is used to call asynchronous functions is the “callback” function.
We have already made use of this “pattern” on several occasions:
Making XMLHttpRequests
Invoking array methods such as “.map()” and “.filter()”
Callbacks have been in use for a long time and when used “sparingly” they do their job quite well.
However, when one has need to invoke a series of asynchronous functions where the output of each
one is required as input to another one, we can create a situation commonly referred to a “Callback
Hell.”
The code shown in this slide can be found in the “CodeExamples” folder: “CallBackHell2.html”
As explained on the slide, when preparing an “all-beef” hamburger there are several steps involved and
each step along the way is dependent upon a step which must be completed before it can be started.
This results in callbacks nested within callbacks, which when indents are properly used results in a
“telltale” sideways “V” pattern as can be seen above.
While this approach works, it can be difficult for others to follow and is both prone to errors and difficult
to debug.
The above diagram shows the basic structure of creating a “Promise” and then getting the result back by
resolving the “Promise.”
If you open the file “XMLHttpReqPromise.html” from the “CodeExamples” folder you will see an
example of using a “Promise” to call an asynchronous process.
In the above code on line 17, we define a function which returns a “new Promise” object. The
“Promise” will resolve to the “JSON” returned from a call to the “ist.rit.edu.api/minors” API which
retrieves details about the minors available for each “iSchool” undergraduate degree.
To create the “Promise,” we pass a function into the “Promise’s” constructor. The function takes two
parameters: “resolve” and “reject.” Each of these parameters are themselves functions.
To “fulfill” the “Promise,” we invoke, on line 29, “resolve” passing in the values that will be passed into
the first parameter of the “Promise’s” “then” method, line 43.
“Reject” works similarly except it is for any errors. It is passed to the second parameter of the
“Promises” “then” method.
While I do not have an example ready, we can chain “then” calls together to create a sequence of
asynchronous calls where each call is dependent on the call before it in the sequence completing. This
works because each “then” method returns yet another promise. This is a lot cleaner to maintain then
“nested” callbacks.
The above output was created in by the “resolve()” on line 29, passing back the “rspnsTxt” as the first
parameter of the “Promise.” Take some time to work through the code that is used to build the output;
open up “Developer Tools” in your browser and go to the “Sources” tab to examine the JavaScript code
and add breakpoints to see the array values at each stage – you will need to understand this for “Project
2.” The data we get back is in the form of arrays and a number of jQuery “$.each()” calls, equivalent to
ES6 “array.forEach,” are used to “parse” the arrays and produce the output you see above.
In the case of an error, “rspnsTxt.onerror” on line32, will return an error message to the second
parameter of the “then” method, “error.”
I will now open the “Sources” tab in the browsers “Developers tools” so we can examine the state of the
“Promise” during the running of the program.
First, I will add a breakpoint on line 25, and start up the program.
When the breakpoint on line 25, is hit and I place my mouse over the “promise” definition on line 39, I
see the following:
At this point in processing the “PromiseState” is pending and our “PromiseResult” is undefined since we
have not yet had the data from the server returned.
If I put a second breakpoint on line 44, at which point we should have received our response and
continue running the program we see the following:
As you can see the “Promise” is now fulfilled and the “PromiseResult” is the data returned from
“ist.rit.edu.api/minors,” “gMinors” is the undergraduate minors array we will parse through.
While we have not specifically talked about it yet, as mentioned earlier “jQuery.ajax()” uses “deferred
objects” which are like “Promises.”
If you examine the jQuery.ajax call starting on line 28, you will notice on line 35, a “fail()” method
definition. Additionally, on line 12, “chained” to the “myXHR” function which invokes the “jQuery.Ajax”
call is a “.done()” method.
Each of these method invocations serve the same purpose as the “then()” method for “Promises.”
You can look at a sample program using the “fetch” specification – open “FetchA.html” from
“CodeExamples.”
“Fetch,” as mentioned, is similar to “jQuery.ajax” and as you can see in the above code example it is
coded in a similar style.
The following techniques will help you “parse” responses from any of the endpoints available on
“isr.rit.edu.api/…”
The following is the code that produces the output for the “minors” endpoint.
In the source code available on the “Sources tab” I have placed breakpoints on lines 45, 46, 47, and 48.
When we “break” on line 45, we can see the “jsonResponse” on the right-hand side. It is a JavaScript
array with the property “UgMinors,” “undergraduate minors,” and a value which is an array of length 8,
containing information of the 8, available minors.
On line 46, we have the results of applying the “$.each()” method to the “jsonResponse.” We have
“index” from the callback set to “UgMinors” and “value” set to the 8, element array containing
information on the minors.
At the next breakpoint we have index1 = 0; which is the index of the first element of the array containing
the information on the first of the minors: “name: DBDDI-MN.”
In the final breakpoint we have now started to iterate through the array element for the minor “name:
DBDDI-MN.” If you look at the data outlined in red on the right, you will see the “index” name and
“value” for the name.
We append this data to the “content” area in the HTML body where we will display the data. Each
iteration of the “$.each(value1, function(index2, value2)” method will append the next “index / value”
pair to the “content” area; notice a <br> is appended to put line breaks in.
When the iteration of this array element is done, we iterate over the next element of the “UgMinors”
array. We continue this until we are finished with all the minors.
As an exercise which will come in handy for “Project 2” look up the “COURSES” on “ist.rit.edu/api.” You
can use the array associated with the “courses” property from this array to look up the details of each of
the courses listed here.
As an example, for the minor with name: DBDDI-MN, the list of courses is courses: ISTE-230,ISTE-
430,ISTE-330,ISTE-436,ISTE-432,ISTE-434. You would place those names, e.g. “ISTE-230,” into the
(course-name) parameter in the above.