Asynchronous code Flashcards
debugging
chrome: Sources/Page/find the file –> place break point
js is a single threaded language
whatever script is being running , the single JS thread is running at most one line of JS code
if we send a request to server, it takes time for the response to come back. In the meantime, nothing is supposed to run. But browsers have a workaround to accomplish something while waiting for response
JS is not the same as the browser. JS is not actually waiting, it hands over tasks to the browser. And then the browser, which is written say in C++, decides how to handle them.
So if we have
console.log(“1”);
setTimeout(() => {…}, 3000)
console.log(“2”);
the second console.log will print before setTimeout
this is what the browser is handling, not JS
JS and browser
Browsers come with Web APIs that are able to handle certain tasks in the background - like making requests or setTimeout
JS call stack recognizes these Web API functions and passes them off to the browser to take care of
Once the browser finishes those tasks, they return and are pushed onto the stack as a callback
So JS’s single thread is not blocked by setTimeout or requests because they are passed to the browser and run in the background. So there is a list of certain functions that JS hands over to the browser to handle.
For ex., console.log is not passed to the browser, because JS knows how to handle it itself
In the case of setTimeout browser waits for the specified time (3 seconds here) and then places the specified callback onto the stack for JS to perform
setTimeout(() => {…}, 3000)
so first JS hands over a function to browser and then the browser puts it back on the call stack for JS to perform
This is how we get around the fact that JS is not a multitasker
promises
a pattern for writing async code
an object representing the eventual completion or failure of an asynchronous operation (smth that takes time), a value that you don’t have at the moment
promise basic structure
catch in this case catches errors from any then in the chain
const promise = new Promise((resolve, reject) => { if(smth) resolve(); else reject(); })
so we have a callback which itself has two parameters, that are in turn callbacks again - resolve (fulfill the promise) and reject (reject promise). If promise is not rejected or resolved, for ex., if the body of the callback is empty and they are never called, promise remains in status pending. So we need to specify under which conditions we reject or resolvre
every promise has a .then method which will run if the promise is resolved
promise.then(() => {});
.catch(() => {}); will run if the promise is rejected
we can also chain them
then().catch()
if in then() we return a promise so we can also do
then().then().then().catch()
so when something returns resolved we can send another request
axios returns a promise that we can use to specify what to do in case of success or failure
axios.get(“google.com”).then(callback).catch(callback)…
reject and resolve with data (ex., status code)
we can pass any number of arguments into reject and resolve
reject({status: 404})
and then we can use it in catch
catch((result) => {})
in resolve we can pass some data in the same way
fetch
not supported in IE!! but it is native JS!! as opposed to axios
main advantage - supports promises
fetch returns a Promise object
fetch(urlPath, ).then((response) => {
console.log(response.json().then((data) => console.log(data)));
}).catch((err) => {
});
response.json also returns a promise, so we need an extra step to print the data
IMPORTANT! on error status 404 or 500 - it will not reject, so the code will not go into catch, it will be processed in then. To work around this, you can check for these codes and throw new Error(“”) so that it is forwarded into the catch block
MDN Fetch API - docs
fetch also supports chaining promises
IMPORTANT how then() chaining works!!!!
fetch(url) .then((response) => { if(!response.ok) throw new Error(`Status code ${response.status}`); return response.json; }).then((data) => { const newUrl = data.results[0]...//some code to extract url from the previous response; return fetch(newUrl); }).then((response) => { if(!response.ok) throw new Error(`Status code ${response.status}`); return response.json; }).then((data) => { console.log(data); }).catch((err) => { console.log("smth went wrong"); })
fetch() gives us a promise, that is used in the first then to return response in json format. The second then is executed after the first one and on the value that is returned by it. The first then returns response as json, the second then extracts another url from this response data and executes another fetch, which in turn gives us another response that is parsed in the following then.
If anywhere along the way an error happens, it is caught in catch
you can pass any data to the next then by simply doing
return Promise.resolve(data);
axios
not native JS, external library, uses fetch behind the scenes
Promise-based
can be used both on the client side and on the server side (using nodejs)
to use it - add
with fetch we need to use response.json() which returns Promise that we need to parse, we also need to check error status, because it is not always passed to catch (404, 500), but with axios you don’t need to do that
Everything not 200 will be caught in catch (at least all 4.. and 5…)
axios.get(url).then((response) => {
console.log(response.data);
}).catch((err) => {
console.log
});
OR with destructuring
axios.get(url).then(({data}) => {
console.log(data);
}).catch((err) => {
console.log(err);
});
axios.get returns Promise
axios with chaining
axios.get(url) .then(({data}) => { return axios.get(data.next); }) .then(({data}) => { console.log(data); }).catch...
async functions
syntactical sugar for promises
- async
- await
async
in front of function
if you do this, the function will always return a promise, no matter what you really return inside the function
For ex., even if you return a string
await
we put it inside an async function and it will pause the execution of the function until the promise is resolved
so instead of writing the whole .then() thing we can just use await
async function getP(){ const result = await axios.get(url); console.log(result.data); }
in this case, now because we are using async and await - console.log line will be executed only after the axios response is received into the variable result
without await console.log will throw an error, because it will be executed before response is received and result would be undefined
we also need to handle reject somehow in this case
- getP().catch((err) => {
console.log(err);
});
2. async function getP(){ try{ const result = await axios.get(url); console.log(result.data); }catch(e){ console.log(e); } }
async await and parallel execution
let's say we have several awaits that should run in parallel const result1 = await axios.get(url1); const resul2 = await axios.get(url2); console.log(result1.data); console.log(result2.data);
this will run sequentially because of the await. What if we want the first two lines to run in parallel (faster)
2 ways to solve
const promise1 = axios.get(url1); const promise2 = axios.get(url2);
const result1 = await promise1; const result1 = await promise2;
console. log(result1.data);
console. log(result2.data);
2. const promise1 = axios.get(url1); const promise2 = axios.get(url2);
const results = await Promise.all([promise1, promise2]); console.log(results) //an array of two promises