Asynchronous JavaScript
- JS is single threaded --- i.e. two bits of script cannot run at the same time, they have to run one after another
- usually JS runs code sequentially in top-down order --- but sometimes there is code that runs (or must run) after something else happens and also not sequentially --- this is asynchronous programming
Callbacks
- we use callback functions to make sure a function won't run before a task is completed but will run right after it is completed
- they are passed as parameters to other functions
- can be named, anonymous, or an arrow function
// named const message = function () { console.log('This message is shown after 3 seconds'); } setTimeout(message, 3000); // anonymous setTimeout(function () { console.log('This message is shown after 3 seconds'); }, 3000); // arrow setTimeout(() => { console.log('This message is shown after 3 seconds'); }, 3000);
- callbacks commonly used in event declarations --- e.g. a message that occurs when a button is clicked
Promises
- "Quick recap: in Javascript, a Promise is an object used as a proxy for a value not yet known. It’s called a Promise because it’s saying “I may not know what the value of the return is right now, but I promise to return it at some point, stored inside this thing”. In that way , instead of immediately returning the final value (which a synchronous method would do ), Promises allow you to use an asynchronous method, get the final value, and queue up “next steps” that you want to run on the eventually-returned value,..." source
- a promise is a special JavaScript object that links the 'producing code' and the 'consuming
code' together
- 'producing code' does something and takes time
- 'consuming code' wants the result of the 'producing code' once it's ready
- the 'producing code' takes whatever time it needs to produce the promised result, and the promise makes that result available to the 'consuming code' when it's ready
// constructor syntax
let promise = new Promise(function(resolve, reject) {
// executor (the producing code)
});
- the function passed to
new Promise
is called the executor --- whennew Promise
is created it runs automatically --- it contains the producing code which should eventually produce the result - the
resolve
andreject
are callbacks provided by JS --- our only code is within the executor - the promise object returned by the
new Promise
constructor has these internal properties:- state: initially 'pending', then changes to either 'fulfilled' when
resolve
is called or 'rejected' whenreject
is called - result: initially undefined, then changes to
value
whenresolve(value)
is called orerror
whenreject(error)
is called
- state: initially 'pending', then changes to either 'fulfilled' when
So the executor eventually moves the promise to one of these states:
- example of 'fulfilled promise':
let promise = new Promise(function (resolve, reject) { // after 1 second, signal that the job is done with the result 'done' setTimeout(() => resolve('done'), 1000); });
- example of 'rejected promise':
let promise = new Promise(function (resolve, reject) { // after 1 second, signal that the job is done with the result 'done' setTimeout(() => reject(new Error ('Whoops!')), 1000); });
- a promise that is either resolved or rejected is called 'settled' (as opposed to the initial state of 'pending')
- the executor should call only one ---
resolve
orreject
--- any state change is final (immutable) --- all further calls ofresolve
andreject
are ignored resolve
/reject
expect only one argument (or none) and will ignore any additional arguments- usually an executor does something asynchronously and calls
resolve
/reject
after some time --- but we can call them immediately - the properties
state
andresult
of the Promise are internal --- they can't be directly accessed --- we can use.then
,.catch
, and.finally
for that
Consumers: then, catch, and finally
then
- the first argument of
.then
is a function that runs when the promise is resolved, and receives the result - the second argument is a function that runs when the promise is rejected, and receives the error
- syntax:
promise.then( function(result) { /* handle a successful result */ }, function(error) { /* handle an error*/ } );
catch
- if the promise is rejected, the return value passes through and
.then
s and is picked up by thecatch