JavaScript Is Single-Threaded
Normal JavaScript code only executes on a single thread. That means the lines of code execute one at a time.
Normal JavaScript code only executes on a single thread. That means the lines of code execute one at a time.
We'll see in an upcoming lecture how reactive programming can help mitigate some of these downsides.
init().
let img=document.createElement('img');
//setting src triggers load
img.src='https://pictures.com/mine.jpg'
while (!img.complete) {
// twiddle my thumbs
}
init();
The main thread never finishes executing that while loop, so the asynchronous image load stays blocked too.
setInterval()
let img = document.createElement('img');
img.src = 'https://pictures.com/mine.jpg';
let pollId = setInterval(() => {
if (img.complete) {
init();
}
}, 250);
doOtherStuff();
while loopinit()clearInterval()
let img = document.createElement('img');
img.src = 'https://pictures.com/mine.jpg';
let pollId = setInterval(() => {
if (img.complete) {
clearInterval(pollId);
init();
}
}, 250);
doOtherStuff();
clearInterval() stops future polling once condition is metinit() only runs onceAddEventListenerRemoveEventListenerclearTimeout and clearInterval for timers)init().
let img=document.createElement('img');
img.addEventListener('load',init);
img.src='https://pictures.com/mine.jpg'
doOtherStuff(); //runs during img load
load event is triggered when item finishes loading
let img=document.createElement('img');
img.src='https://pictures.com/mine.jpg'
img.addEventListener('load',init);
doOtherStuff(); //runs during img load
setInterval(() => {
button.textContent = ++i;
}, 500);
img.addEventListener('load', () => {
init();
});
Let's say I'm building a social media app, and I have a database of users. I want to check whether my best friend's best friend is me or not!
Looking up a user in the database is an async API query.
function getUser(userId, callback) { ... }
And to do this lookup we'll need to make several async requests.
getUser("jopo", user => {
getUser(user.bestFriendId, friend => {
getUser(friend.bestFriendId, friendOfFriend => {
console.log(friendOfFriend.name);
});
});
});
getUser("jopo", user => {
getUser(user.bestFriendId, friend => {
getUser(friend.bestFriendId, friendOfFriend => {
console.log(friendOfFriend.name);
});
});
});
getUser("jopo", user => { getUser(user.bestFriendId, friend => { getUser(friend.bestFriendId, friendOfFriend => { console.log(friendOfFriend.name); }); }); });
If we reformat our code slightly differently, we can begin to see a linear chaining pattern that could maybe replace the nesting structure.
getUser("jopo") //returns a promise
.then(user => getUser(user.bestFriendId))
.then(friend => getUser(friend.bestFriendId))
.then(friendOfFriend => {
console.log(friendOfFriend.name);
});
then() method to specify what to do when promise is fulfilled
then()
function getUserPromise (userId) {
return new Promise(fulfiller => {
getUser(userId, fulfiller);
});
}
getUserPromise("jopo")
.then(user => console.log(user.name));
then(f) says f is a callback to invoke when promise is fulfilledf receives value of fulfilled promise
p = delayed("hi",1000);
// promise resolves to "hi"
// after 1000ms
p.then(res => console.log(res));
// console outputs 1000ms later
...lots of code
p.then(res => console.log("bye"));
// if p already fulfilled,
// callback executes immediately
wait(1000) //promise fulfilled after 1000ms
.then(() => console.log(1))
.then(() => console.log(2))
.then(() => console.log(3))
What gets output?
wait(1000) //promise fulfilled after 1000ms
.then(() => console.log(1))
.then(console.log(2))
.then(() => console.log(3))
What gets output?
then() callback can return a value (or a promise of one)then() callback in chain when availablethen() returns a new promise p providing that valuethen() is invoked on pp.then() passes on the value of p
//traditional evaluation style
y = f(g(h(x)));
//promise-based
Promise.resolve(x)
// promise with fulfilled value x
.then(h) //h receives x
.then(g) //g receives h(x)
.then(f) //f receives g(h(x))
.then(res => y=res);
.then() always returns a promise
then() returns thatthen() wraps it in a (already fulfilled) promisethen() returns a promise wrapping undefined
then() in chain invoked on new promisePromise.all() tracks multiple promises running in parallel
let p1=fetch(url1);
let p2=fetch(url2);
let p3=fetch(url3);
Promise.all([p1,p2,p3])
.then([c1,c2,c3] =>
{//process all 3 pieces},
err => {handle the error})
then() callbackthen() can take a second callback
then()
fetch(url)
//returns a promise to provide
// content found at that url
.then(content => {
//executes if fetch is fulfilled
console.log("received" + content);
return 0},
error => {
//executes if fetch is rejected
console.log("error: " + error)
return -1}
})
.then(res => console.log(res))
//logs 0 if fetch succeeded,
// 1 if it failed
.then(f,r) callbacks for when promise resolves
f() invoked if promise fulfilledr() invoked if promise rejectedundefinedp.catch(c): callback c() invoked if promise p is rejected; fulfilled p passed on without change
then(), catch() returns a new promise that can fulfill or rejectp.catch(foo) same as p.then((x)=>x, foo)p.finally(c): callback c() is invoked when promise p is fulfilled or rejectedPromise.race([a,b,c,...]): returns a promise that fulfills as soon as any of a,b,c... doPromise.resolve(x): returns a promise that is already resoled to x
Promise.reject(): returns a promise that is already rejected
async declares an asynchronous function
Promise that will be resolved when the function finishes and returns its “actual” valueawait any promise
await appears synchronous, but it makes that async function pause and wait for the promise to resolve
async function doMyWork() {
console.log('beginning')
let response =
await fetch("countries.json");
let data = await response.json()
console.log(data);
for (let i=1; i<=5; i++) {
let result =
await delayed('answer',5000);
console.log(i + result);
}
return data;
}
async function f () {
x();
a = await(y());
return z();
}
function f () {
x();
p = y()
.then((res) => {a = res;})
.then(z)
return p
}