promises intro to async

69
Intro to Async & Intro to Async & Promises Promises Nick Whyte | @nickw444 | @nickw444

Upload: others

Post on 10-Nov-2021

2 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Promises Intro to Async

Intro to Async &Intro to Async &PromisesPromises

Nick Whyte | @nickw444 | @nickw444

Page 2: Promises Intro to Async

About MeAbout MeFrontend Engineer / Technical Lead @ CanvaGraduated UNSW in 2016 (Computer Science)COMP2041 student in 2014COMP2041 tutor in 2015

Page 3: Promises Intro to Async

What is AsyncWhat is Async

Page 4: Promises Intro to Async

synchronous: Operations can only occur one ata time.asynchronous: Multiple operations can occur atthe same time. Programmers can parallelise theirprogram.

Page 5: Promises Intro to Async

Concurrency modelsConcurrency modelsCoroutines / Cooperative MultitaskingThreads / Preemptive MultitaskingEvent Driven

https://www.cse.unsw.edu.au/~cs9242/18/lectures/02-threadsevents.pdf

Page 6: Promises Intro to Async

Threads / PreemptiveThreads / PreemptiveMultitaskingMultitasking

A thread can be preempted, so mutex's andsemaphores required to guard critical sections &variables.Typical multi-tasking model found in manylanguages like Java and Python.

https://www.cse.unsw.edu.au/~cs9242/18/lectures/02-threadsevents.pdf

Page 7: Promises Intro to Async

Co-routines / CooperativeCo-routines / CooperativeMultitaskingMultitasking

co-routines can cooperatively "yield" to other co-routines."yield" saves the state of co-routine A, andresumes B's state from it's previous yield point.No preemption between yields, so no need formutex's or semaphores to guard critical sections.

https://www.cse.unsw.edu.au/~cs9242/18/lectures/02-threadsevents.pdf

Page 8: Promises Intro to Async

Event DrivenEvent DrivenExternal entities generate (post) events. (i.e.button click)Event loop waits for events and calls anappropriate event handler.Event handler is a function that runs tocompletion and returns to the event loop.No preemption, so no need for mutex's orsemaphoresCannot parallelise computational workloads ☹

https://www.cse.unsw.edu.au/~cs9242/18/lectures/02-threadsevents.pdf

Page 9: Promises Intro to Async

Event DrivenEvent Driven

Page 10: Promises Intro to Async

Javascript Concurrency ModelJavascript Concurrency ModelJavascript is single threaded, event drivenUnable to parallelise computational tasksEach handler is run to completion before a newtask is started

A typical Javascript program will be IO Bound,rather than CPU bound, which means the eventdriven model is appropriate

while (queue.waitForMessage()) { queue.processNextMessage(); }

https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop#Event_loop

Page 11: Promises Intro to Async

Event Loop DemoEvent Loop Demo

Page 12: Promises Intro to Async

callbacks ⇒ {}callbacks ⇒ {}

Page 13: Promises Intro to Async

What is a callbackWhat is a callbackA function that is called when the pending workhas completedCan use either a named function or ananonymous lamdba:fs.readFile('foo.txt', (result, err) => { // Do something with result here })

function onComplete(result, err) { // Do something with result here } fs.readFile('foo.txt', onComplete)

Page 14: Promises Intro to Async

Why Do We Use Callbacks?Why Do We Use Callbacks?Because of the event loopFunctions cannot block whilst they wait for aresult otherwise important tasks on the queuewill be delayedTherefore they must register a completionhandler: A callbackfs.readFile('foo.txt', (result, err) => { if (err) { console.error('Something went wrong:', err) return; } // Do something with result here })

Page 15: Promises Intro to Async

Callback GotchasCallback Gotchas

Page 16: Promises Intro to Async

try-catch with callbackstry-catch with callbacksfunction doThing() { throw new Error('Something went wrong'); } window.setTimeout(() => doThing(), 1000)

Error: Something went wrong

Page 17: Promises Intro to Async

try-catch with callbackstry-catch with callbacksfunction doThing() { throw new Error('Something went wrong'); } try { window.setTimeout(() => doThing(), 1000) } catch (e) { console.log('Caught error on click:', e); }

Page 18: Promises Intro to Async

try-catch with callbackstry-catch with callbacksfunction doThing() { throw new Error('Something went wrong'); } try { window.setTimeout(() => doThing(), 1000) } catch (e) { console.log('Caught error on click:', e); }

Error: Something went wrong

Page 19: Promises Intro to Async

try-catch with callbackstry-catch with callbacksfunction doThing() { throw new Error('Something went wrong'); } try { window.setTimeout(() => doThing(), 0) } catch (e) { console.log('Caught error on click:', e); }

Page 20: Promises Intro to Async

try-catch with callbackstry-catch with callbacksfunction doThing() { throw new Error('Something went wrong'); } try { window.setTimeout(() => doThing(), 0) } catch (e) { console.log('Caught error on click:', e); }

Error: Something went wrong

Page 21: Promises Intro to Async

try-catch with callbackstry-catch with callbacksfunction doThing() { throw new Error('Something went wrong'); } window.setTimeout(() => { try { doThing(); } catch (e) { console.log('Caught error on click:', e); } }), 1000)

Page 22: Promises Intro to Async

try-catch with callbackstry-catch with callbacksfunction doThing() { throw new Error('Something went wrong'); } window.setTimeout(() => { try { doThing(); } catch (e) { console.log('Caught error on click:', e); } }), 1000)

Caught error on click: Something went wrong

Page 23: Promises Intro to Async

Callback HellCallback HellgetData(function(x){ getMoreData(x, function(y){ getMoreData(y, function(z){ ... }); }); });

Page 24: Promises Intro to Async

Resolving Callback HellResolving Callback HellKeep your code shallowDon't nest functions. Give them names and placethem at the top level of your program

Page 25: Promises Intro to Async

When Not To Use CallbacksWhen Not To Use CallbacksWhen your work is synchronous

Page 26: Promises Intro to Async

When Not To Use CallbacksWhen Not To Use Callbacksfunction sayHello(callback) { console.log('Hello!'); callback(); } sayHello(() => { console.log('We said hello.'); });

function sayHello() { console.log('Hello!'); } sayHello(); console.log('We said hello.');

Page 27: Promises Intro to Async

PromisesPromises

Page 28: Promises Intro to Async

What are PromisesWhat are PromisesAn abstraction around async work giving usaccess to “future” values.A Promise is an object representing the eventualcompletion or failure of an asynchronousoperation.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

Page 29: Promises Intro to Async

Promise TerminologyPromise TerminologyA Promise can be:

Ful�lled: The action relating to the promisesucceeded.Rejected: The action relating to the promisefailed.Pending: Hasn't yet ful�lled or rejected.Settled: Has ful�lled or rejected.

https://developers.google.com/web/fundamentals/primers/promises

Page 30: Promises Intro to Async

Using PromisesUsing Promisesfunction callback(results, err) { if (err) { console.error('Something went wrong:', error); return; } console.log('Got the results:', results) } getUsers(callback);

Page 31: Promises Intro to Async

Using PromisesUsing Promisesconst promise = getUsers(); promise .then(results => { console.log('Got the results:', results) }) .catch(error => { console.error('Something went wrong:', error) })

Page 32: Promises Intro to Async

.then.then

Returns a promiseonFul�lled: A function called if the promise isful�lled. It receives the ful�llment value as anargument.onRejected: (optional) A function called if thepromise is rejected. It receives the rejectionreason as an argument.

p.then(onFulfilled[, onRejected]);

Page 33: Promises Intro to Async

.then.thenA handler can:

return a valuethrow an errorreturn a promise

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then#Return_value

Page 34: Promises Intro to Async

.catch(.catch(

The catch() method returns a Promise and dealswith rejected cases onlyInternally calls Promise.prototype.then

p.catch(onRejected);

Page 35: Promises Intro to Async

Chaining / CompositionChaining / CompositiongetUsers() .then(users => getUserProfile(users[0])) .then(userProfile => downloadUserImage(userProfile.image.url)) .then(userImage => { console.log('Downloaded user profile image') }) .catch(error => { console.error('Something went wrong:', error) })

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises#Chaining

Page 36: Promises Intro to Async

Chaining / CompositionChaining / Composition

By chaining promises, we avoid "callback hell"

doSomething(result => { doSomethingElse(result, newResult => { doThirdThing(newResult, finalResult => { console.log('Got the final result: ' + finalResult); }, handleFailure); }, handleFailure); }, handleFailure);

doSomething() .then(result => doSomethingElse(result)) .then(newResult => doThirdThing(newResult)) .then(finalResult => { console.log('Got the final result: ' + finalResult); }) .catch(handleFailure);

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises#Chaining

Page 37: Promises Intro to Async

Handling ErrorsHandling ErrorsA promise chain stops if there's an exception andlooks down the chain for a catch handler insteaddoSomething() .then(result => doSomethingElse(result)) .then(newResult => doThirdThing(newResult)) .then(finalResult => console.log(`Got the final result: ${finalR .catch(failureCallback);

try { const result = syncDoSomething(); const newResult = syncDoSomethingElse(result); const finalResult = syncDoThirdThing(newResult); console.log(`Got the final result: ${finalResult}`); } catch(error) { failureCallback(error); }

Page 38: Promises Intro to Async

Handling ErrorsHandling ErrorsA catch statement can be used to continue thechain after a failurefetchUsers() .then(() => { throw new Error('Something failed'); console.log('Do this'); }) .catch(() => { console.log('Do that'); }) .then(() => { console.log('Do this, no matter what happened before'); });

Do that Do this, no matter what happened before

Page 39: Promises Intro to Async

Creating PromisesCreating Promises// returns a Promise object that is rejected with the given reasoPromise.reject(new Error('Something went wrong!'));

// returns a Promise object that is resolved with the given value Promise.resolve('I am resolved!');

new Promise((resolve, reject) => { doSomethingAsync((result, err) => { if (err) { reject(err); return; } resolve(result); }) })

Page 40: Promises Intro to Async

PromisifyPromisifySometimes useful to promisify a callback API to

support chainingfunction wait(ms) { return new Promise(resolve => { setTimeout(resolve, ms); }); } wait(1000) .then(() => { console.log('Waited for 1 second'); })

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises#Creating_a_Promise_around_an_old_callback_API

Page 41: Promises Intro to Async

Promise.all()Promise.all()Returns a Promise that resolves when all of thepromises have settledIt rejects with the reason of the �rst promise thatrejects.const p = Promise.all([ doSomething(), doSomethingElse() ]); p.then(results => { // results[0] is the result of doSomething() // results[1] is the result of doSomethingElse() })

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all

Page 42: Promises Intro to Async

Promise.race()Promise.race()Returns a promise that resolves or rejects assoon as one of the promises resolves or rejects.Resolves or rejects with the value or reason fromthat promise.const p = Promise.race([ doSomething(), doSomethingElse() ]); p.then(result => { // result is the value of either doSomething or doSomethingElse // whichever resolved first. })

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/race

Page 43: Promises Intro to Async

When not to use PromisesWhen not to use PromisesIf you're doing synchronous workWhen you have a callback situation where thecallback is designed to be called multiple timesFor situations where the action often does not�nish or occur

https://stackover�ow.com/a/37531576

Page 44: Promises Intro to Async

Promise hellPromise hellSimple promise chains are best kept �at without

nesting, as nesting can be a result of carelesscomposition.

fetchBook() .then(book => { return formatBook(book) .then(book => { return sendBookToPrinter(book); }); });

fetchBook() .then(book => formatBook(book)) .then(book => sendBookToPrinter(book));

https://medium.com/@pyrolistical/how-to-get-out-of-promise-hell-8c20e0ab0513https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises#Nesting

Page 45: Promises Intro to Async

async-awaitasync-awaitSyntactic sugar around PromisesAllows you to write async functions more likesynchronous functions

Page 46: Promises Intro to Async

async-awaitasync-awaitdoSomething() .then(result => doSomethingElse(result)) .then(newResult => doThirdThing(newResult)) .then(finalResult => console.log(`Got the final result: ${finalR .catch(failureCallback);

try { const result = await doSomething(); const newResult = await doSomethingElse(result); const finalResult = await doThirdThing(newResult); console.log(`Got the final result: ${finalResult}`) } catch (e) { failureCallback(e); }

Page 47: Promises Intro to Async

async-awaitasync-awaitThe await keyword is only valid inside asyncfunctionsasync myAsyncFunction() { await doSomething(); await doSomethingElse(); } const p = myAsyncFunction(); // typeof p === Promise p .then(() => { ... }) .catch(() => { ... })

Page 48: Promises Intro to Async

CancellationCancellationYou can’t cancel a PromiseThis poses potential issues when using promisesfor long running tasksThere are third party libraries that supportcancellation (Bluebird)If you want cancellation, Promises might not bewhat you want

Page 49: Promises Intro to Async

Fetching Data / AJAXFetching Data / AJAX

Page 50: Promises Intro to Async

Fetching Data / AJAXFetching Data / AJAXFetch partial data from the serverUpdate content on a page without refreshing itentirelySubmit user input to the server without POST'inga form / reloading the page

Page 51: Promises Intro to Async

Fetching Data / AJAXFetching Data / AJAX

Page 52: Promises Intro to Async

XHR (sync)XHR (sync)

Run Code

console.log('Loading...'); const request = new XMLHttpRequest(); // `false` makes the request synchronous request.open('GET', 'https://api.ipify.org?format=json', false); request.send(null); if (request.status === 200) { console.log(request.responseText); }

https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Synchronous_and_Asynchronous_Requests#Synchronous_request

Page 53: Promises Intro to Async

XHR (async)XHR (async)

Run Code

console.log('Loading...'); const xhr = new XMLHttpRequest(); xhr.open("GET", "https://api.ipify.org?format=json", true); xhr.onload = function (e) { if (xhr.readyState === 4) { if (xhr.status === 200) { console.log(xhr.responseText); } } }; xhr.send(null);

https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Synchronous_and_Asynchronous_Requests#Asynchronous_request

Page 54: Promises Intro to Async

XHR Util with CallbackXHR Util with Callbackfunction getData(url, onSuccess, onError) { var xhr = new XMLHttpRequest(); xhr.open('GET', url, true); xhr.onload = function(e) { if (xhr.readyState === 4) { if (xhr.status === 200) { onSuccess(xhr.responseText); } else { onError(new Error(xhr.statusText)); } } }; xhr.onerror = function(e) { onError(new Error(xhr.statusText)); } xhr.send(null); };

getData('https://mysite.com/foo.json', result => { console.log('Got data:', result); }, error => { console.log('An error occurred:', error) })

Page 55: Promises Intro to Async

XHR with PromiseXHR with Promisefunction getData(url) { return new Promise((resolve, reject) => { var xhr = new XMLHttpRequest(); xhr.open('GET', url, true); xhr.onload = function(e) { if (xhr.readyState === 4) { if (xhr.status === 200) { resolve(xhr.responseText); } else { reject(new Error(xhr.statusText)); } } }; xhr.onerror = function(e) { reject(new Error(xhr.statusText)); } xhr.send(null); }); };

try { const data = await getData('https://mysite.com/foo.json'); console.log('Got data:', result); } catch (error) { console.log('An error occurred:', error) }

Page 56: Promises Intro to Async

fetch()fetch()The Fetch API provides an interface for fetchingresourcesMore powerful and �exible feature set thanXMLHttpRequest

https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API

Page 57: Promises Intro to Async

Using Using fetch()fetch()Similar to our Promisi�ed XMLHttpRequestattemptWon’t reject on HTTP error status (You will needto compose a chain to reject if you need this)Call Response.json() to deserialize a JSONresponsefetch('http://example.com/movies.json') .then(response => response.json()) .then(myJson => { console.log(myJson); });

https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch

Page 58: Promises Intro to Async

Single PageSingle PageApplications (SPA's)Applications (SPA's)

Page 59: Promises Intro to Async

Single Page ApplicationsSingle Page Applications(SPA's)(SPA's)

A website that re-renders its content in responseto user actions (i.e. clicking a link) withoutreloading the entire pageWill make use of XHR/fetch to load partialcontent on user actionsEasy to build with the right tools (Angular, React+ React-Router, Vue)Feels more responsive to users

Page 60: Promises Intro to Async

SPA ProsSPA ProsFeels more responsive to users - low latency toswitch between "pages"Explicit split between "frontend" and "backend"architecture"

Page 61: Promises Intro to Async

SPA ConsSPA ConsDi�cult to optimize for search enginesOften quite large to load initially. Bundles > 1MBMemory leaks are more likelyRouting and Navigation is di�cult to get right

Page 62: Promises Intro to Async

SPA ExamplesSPA ExamplesGmail

Page 63: Promises Intro to Async

FrameworksFrameworks

Page 64: Promises Intro to Async

jQuery (2006 → present)jQuery (2006 → present)One of the �rst web "frameworks"Designed to simplify client side scriptingMost widely adopted JS library (still plaguing sitestoday)jQuery's syntax is designed to make it easier tonavigate a document

https://en.wikipedia.org/wiki/JQuery

Page 65: Promises Intro to Async

Backbone (2010 → 2016)Backbone (2010 → 2016)Known for being lightweight as it only had asingle dependencyDesigned for developing single page applicationsAssisted in keeping various parts of webapplications synchronised.

https://en.wikipedia.org/wiki/Backbone.js

Page 66: Promises Intro to Async

Angular/AngularJS (2010 →Angular/AngularJS (2010 →present)present)

Provides a framework for client-side MVCapplication architectures"Magical" DOM data bindingAngular 2+ versions are simply called Angular.Angular is an incompatible rewrite of AngularJS

Page 67: Promises Intro to Async

React (2013 → present)React (2013 → present)React does not attempt to provide a complete'application framework'Similar to Vue, it is designed speci�cally forbuilding user interfacesComplex React applications require the use oflibraries for state management, routing, etc.

https://en.wikipedia.org/wiki/React_(JavaScript_library)

Page 68: Promises Intro to Async

Vue (2014 → present)Vue (2014 → present)Built to organize and simplify web development.Less opinionated that other frameworks(angular) thus easier for developers to pick up.Features an incrementally adoptablearchitecture.Advanced features required for complexapplications such as routing, state managementand build tooling are o�ered via o�ciallymaintained supporting libraries and packages.

https://en.wikipedia.org/wiki/Vue.js

Page 69: Promises Intro to Async

ThanksThanksNick Whyte | @nickw444 | @nickw444

p.s. we are looking for summer interns and 2019 graduates! Please email [email protected] if you are interested