JavaScript is a single-threaded language which means it has a single call stack. This means that JavaScript in the browser can only do one thing at at time.
As a result, if we have a stack of operations to perform and one of them is really slow, everything else has to wait until the slow operation completes. This is called blocking.
So when we get a network request, we have two options:
1. Do the network request right away, and block everything else.
2. Queue the network request, and run it when we have some spare time.
This used to be done with callbacks
fetchFromSomeApi(function(data) {
// now we have the data we need
})
but say you had to make 3 requests:
fetchFromSomeApi(function(data1) {
fetchFromSomeOtherApi(function(data2) {
fetchFromSomeOtherOtherApi(function(data3) {
// well this is confusing.
// and what if one of these goes wrong?
})
})
})
So we moved on, and in ES2015, we gained Promises.
A resolved promise can be said to have fulfilled.
A rejected promise is said to have been rejected.
A promise can also be pending, where we don't know the state. For example, we made a network request but haven't had a response back.
this is how we give a function that will be called with the value inside the box.
promise functions can return the next value
Promise.resolve(5)
.then(value => {
return value + 1;
}).then(value => {
console.log(value)
})
npm run exercise async 1
open the console!
setTimeout(() => {
console.log('I will run after 5 seconds!')
}, 5000)
const timeoutPromise = new Promise(function(resolve) {
setTimeout(() => resolve(), 5000)
})
timeoutPromise.then(() => {
console.log('I will run after 5 seconds')
})
when we create a new promise, we get a function that we can call when we want the promise to resolve
const timeoutPromise = new Promise(function(resolve) {
setTimeout(() => resolve(), 5000)
})
timeoutPromise.then(() => {
console.log('I will run after 5 seconds')
})
npm run exercise async 2
Promise.resolve(5).then(value => {
throw new Error('Jack made this promise go wrong on purpose')
})
"uncaught"
Promise.resolve(5).then(value => {
throw new Error('Jack made this promise go wrong on purpose')
}).catch(e => {
console.log('We caught the error!')
})
npm run exercise async 3
we catch the error and deal with it
and return a new value
does this get run?
npm run exercise async 4
npm run exercise async 5
fetch('https://jsonplaceholder.typicode.com/todos/1')
.then(response => {
return response.json()
})
.then(todo => {
console.log('got todo')
})
fetch('https://jsonplaceholder.typicode.com/todos/1')
.then(response => {
return response.json()
})
.then(todo => {
console.log('got todo')
})
returns a promise that resolves with the response, parsed to JSON.
npm run exercise async 6
npm run exercise async 7
npm run exercise async 8
Promise.all([
Promise.resolve(5),
Promise.resolve(6)
]).then(values => {
console.log(values) // [5, 6]
})
fetch('/posts').then(response => response.json()).then(posts => {...})
const posts = await fetch('/posts').then(response => response.json())
const fetchPhoto = async id => {
const response = await fetch(
`https://jsonplaceholder.typicode.com/photos/${id}`
)
return response.json()
}
we don't need await here because the return value is automatically wrapped in a promise, because our function is async
npm run exercise async 9
const fetchPhoto = async id => {
const response = await fetch(
`https://jsonplaceholder.typicode.com/photos/${id}`
)
return response.json()
}
Promise.resolve(5)
.then(value => value + 1)
.then(value => value + 2)
.then(value => value + 3)
.then(value => {
logPromiseValue(1, value)
})
const asyncVersion = async () => {
const firstValue = await Promise.resolve(5)
logPromiseValue(2, firstValue + 1 + 2 + 3)
}
npm run exercise async 10
npm run exercise async 11
try {
const response = await fetch('/photos')
} catch (e) {
// got an error!
}
try {
const response = await fetch('/photos')
const nextThing1 = await fetch(...)
const nextThing2 = await fetch(...)
const nextThing3 = await fetch(...)
const nextThing4 = await fetch(...)
} catch (e) {
// this will catch all errors from above.
}
npm run exercise async 12
const photos = await fetchAllPhotos()
const albums = await fetchAllAlbums()
these are not run in parallel!
we will wait for photos before fetching albums
const photosAndAlbums = await Promise.all([
fetchPhotos(),
fetchAlbums()
])
this will run in parallel as we expect
npm run exercise async 13
https://stackoverflow.com/a/28709165