Try...catch, Asynchronous JavaScript - promise, async, await, event loop ...
Tags: trycatch, promise, asyncawait, javascript
Published: 2021-12-14 14:58:52

# Destructuring assignment
Destructuring assignment is a JavaScript expression that makes it possible to **unpack values from arrays, or properties from objects, into distinct variables.** [Destructuring assignment -mdn](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment)

```js
let arr = ["Hailey", "Ji"]
let [firstName, surname] = arr;

console.log(firstName); // Hailey
console.log(surname); // Ji
// using destructuring assignment,
// arr[0] was assigned to first name
// arr[1] was assigned to surname

let arr2 = [20, ["Haily", "Ji"]];
let [age, [firstName, surname]] = arr2;

console.log(age); // 20
console.log(firstName); // Hailey
console.log(surname); // Ji

let user = {};
[user.name, user.surname] = "Hailey Ji".split(' ');

console.log(user.name); // Hailey;
console.log(user.surname); // Ji
console.log(user)
// {name: 'Hailey', surname: 'Ji'}


let a = [[1, 2], [3, 4], [5, 6]];

for (let [i, j] of a){
    console.log(i, j);
}
// 1 2
// 3 4
// 5 6
```
More about [destructuring assignment -javascript.info](https://javascript.info/destructuring-assignment)


# try...catch
When executing JavaScript code, different errors can occur.
try...catch statement marks a block of statements to try and specifies a response should an exception be thrown.
The **`try`** statement allows you to **define a block of code to be tested for errors while it is being executed**.
The **`catch`** statement allows you to **define a block of code to be executed, if an error occurs in the try block.**
```js
try {
  alert('Start of try runs');  // (1) <--
  lalala; // error, variable is not defined!
  alert('End of try (never reached)');  // (2)
} catch (err) {
  alert(`Error has occurred!`); // (3) <--
}
```
At above code, the first and third alerts will be executed only. The second alert won't be executed because **lalala is not defined variable which occurs an error**. Therefore, the second will be skipped and then go to **`catch`** and will execute the third alert.

```js
let json = "{ bad json }";

try {
  let user = JSON.parse(json); // <-- error occurs here
  alert( user.name ); // this code will never run

} catch (error) {
  // when error occurs, try execution is stopped, and control flows to the beginning of catch.
  console.log( "There was an error with data." );
  console.log(error.name ); // this way you can check the error
  console.log(error.message ); // and error message
  console.error(error) // this throw error on console(it's used a lot to check the error)
}  
```

JavaScript has many built-in constructors for standard errors: Error, SyntaxError, ReferenceError, TypeError and others.
```js
let error = new Error(message);
// or
let error = new SyntaxError(message);
let error = new ReferenceError(message);


// *** For built-in errors (not for any objects, just for errors), the name property is exactly the name of the constructor. And message is taken from the argument

let error = new Error("Something happened!");

alert(error.name); // Error
alert(error.message); // Something happened!
```


```js
let json = '{ "age": 30 }'; // incomplete data
 
try {
  let user = JSON.parse(json); // <- no error
  if (!user.name) {
    throw new SyntaxError("Incomplete data - no name");
    // SyntaxError with the given message, will generate error message the same way as JavaScript would generate it itself.
  }
  alert(user.name);
} catch (err) {
  alert("JSON Error: " + err.message); // JSON Error: Incomplete data - no name
}
```

# try...catch...finally
If finally exists, in runs always no matter what.

```js
try {
   ... try to execute the code ...
} catch (err) {
   ... handle errors ...
} finally {
   ... execute always ...
}


try {
  alert('try block');
  if (confirm('Make an error?')) BAD_CODE();
} catch (err) {
  alert('catch');
} finally {
  alert('finally');
}
```


### How to use try...catch
```js
class ValidationError extends Error {
  constructor(message) {
    super(message);
    this.name = "ValidationError";
  }
}

function readUser(json) {
  let user = JSON.parse(json);

  if (!user.age) {
    throw new ValidationError("No field: age");
  }
  if (!user.name) {
    throw new ValidationError("No field: name");
  }

  return user;
}

// using try..catch and readUser
try {
  let user = readUser('{ "age": 25 }');
} catch (err) {
  if (err instanceof ValidationError) {
    alert("Invalid data: " + err.message); // Invalid data: No field: name
  } else if (err instanceof SyntaxError) { // (*)
    alert("JSON Syntax Error: " + err.message);
  } else {
    throw err; // throw unknown error. (**)
  }
}
```
More about [try..catch -javascript.info] (https://javascript.info/try-catch)

# Promise
Promise is like a promise that you make that you don't know when you are going to call it but will call it no matter what.
There are only success(completion) and failure for the result.
The Promise object represents the eventual completion (or failure) of an **asynchronous operation** and its resulting value.
A Promise is in one of these states:
- **pending**: initial state, neither fulfilled nor rejected.
- **fulfilled**: meaning that the operation was completed successfully.
- **rejected**: meaning that the operation failed.

```js
// example
let promise = new Promise(function(resolve, reject) {
  // the function is executed automatically when the promise is constructed

  setTimeout(() => resolve("done"), 1000); // after 1 second signal that the job is done with the result "done"
});
console.log('hello world');
console.log(promise);
```
![promise1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6lq7xvgg5crbhhaa3i85.png)
As you can see above, Promise {<pending>} became Promise {<fulfilled>: 'done'} after 1000ms.

```js
let promise = new Promise(function(resolve, reject) {
  setTimeout(() => resolve("Done!"), 3000);
});

console.log('hello world');
promise.then(resolve => console.log(resolve));
console.log('hello world2');

// hello world
// hello world2
// Done!
```
```js
new Promise((resolve, reject) => {...code...})
  .then(...code...)
  .then(...code...)
  .finally(...code...)
  .catch(...code...); // <-- can handle error at .catch
```

```js
new Promise(function(resolve, reject) {
  setTimeout(() => resolve(1), 1000); // (*)
}).then(function(result) { // (**) // result is 1 here.
  console.log(result); // 1
  return result * 2;
}).then(function(result) { // (***)  // result is 2 here.
  console.log(result); // 2
  return result * 2;
}).then(function(result) { // result is 4 here
  console.log(result); // 4
  return result * 2;
});

// 1
// 2
// 4


let p = new Promise(function(resolve, reject) {
  setTimeout(() => resolve(1), 10000); // (*)
}); // runs in 10s
console.log('hello world'); // it gets executed right away
let p2 = p.then(function(result) { // (**)
  console.log(result); // 1
  return result * 2;
}); // when above code gets executed, then receive result and then run the code.
console.log('hello world2'); // it gets executed right away
let p3 = p2.then(function(result) { // (***)
  console.log(result); // 2
  return result * 2;
}); // when above code gets executed, then receive result and then run the code.
console.log('hello world3'); // it gets executed right away
let p4 = p3.then(function(result) {
  console.log(result); // 4
  return result * 2;
});

// hello world
// hello world2
// hello world3
// 1
// 2
// 4
```
A Promise object serves as a link between the executor and the consuming functions, which will receive the result or error. Consuming functions can be registered (subscribed) using methods .then, .catch and .finally.

.**`then`** : then will be executed when previous code is resolved.

```js
new Promise(function(resolve, reject) {
  setTimeout(() => reject('error'), 1000); // reject
}).then(function(result) { // it won't run because of reject, this will be skipped and go to .catch
  console.log(result + ' : Done well!'); 
  return result + 'one';
}).catch(function(result) { // result is error
  console.log(result + ' : Error occurred!'); 
  return result + 'two';
}).then(function(result) { // receive errortwo as result
  console.log(result + ' : Done well!'); 
  return result + 'three';
});

// error : Error occurred!
// errortwo : Done well!
```

## Promise - finally
```js
new Promise((resolve, reject) => {
  /* do something that takes time, and then call resolve/reject */
})
  // runs when the promise is settled, doesn't matter successfully or not
  .finally(() => stop loading indicator)
  // so the loading indicator is always stopped before we process the result/error
  .then(result => show result, err => show error)

new Promise((resolve, reject) => {
  setTimeout(() => resolve("result"), 2000)
})
  .finally(() => alert("Promise ready"))
  .then(result => alert(result)); // <-- .then handles the result
```
About [Promise -javascript.info](https://javascript.info/promise-basics)
[Promise chaining](https://javascript.info/promise-chaining)

# fetch

The Fetch API provides an interface for **_fetching resources_** (including across the network). It will seem familiar to anyone who has used XMLHttpRequest, but the new API provides a more powerful and flexible feature set. 
```js
fetch('https:/fetch-example.com/data.json')
    .then(function(response) {
        return response.json();
    })
    .then(function(json) {
        console.log(json);
        return json    
    })

// 위에서 전국 1차 접종 퍼센트만 뽑아보기
fetch('https:/fetch-example.com/data.json')
    .then(function(response) {
        console.log(1);
        return response.json();
    })
    .then(function(json) {
        console.log(2);
        console.log(json);
        return json
    })
    .then(function(json) {
        console.log(3);
        console.log(json.filter(s => s['시·도별(1)'] === '전국'));
        return
    })


fetch('https:/fetch-example.com/data.json')
    .then(function(response) {
        console.log(1);
        return response.json();
    })
    .then(function(json) {
        console.log(2);
        console.log(json);
        return json
    })
    .then(function(json) {
        console.log(3);
        console.log(json.filter(s => s['시·도별(1)'] === '전국').map((obj) => obj["1차 접종 퍼센트"]));
        return
    })
```
About [fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API)

## HTTP status codes 
- 1xx informational response – the request was received, continuing process
- 2xx successful – the request was successfully received, understood, and accepted
- 3xx redirection – further action needs to be taken in order to complete the request
- 4xx client error – the request contains bad syntax or cannot be fulfilled
- 5xx server error – the server failed to fulfil an apparently valid request
(https://en.wikipedia.org/wiki/List_of_HTTP_status_codes)

#async, await
An async function is a function declared with the **`async`** keyword, and the **`await`** keyword is permitted within them. The async and await keywords enable <u>**asynchronous, promise-based behavior**</u> to be written in a cleaner style, avoiding the need to explicitly configure promise chains.

```js
async function f() {
  return 100;
}
f().then(alert); // 100
async function f() {
  return 100;
}
f().then(function(result) { // (**) // receive 100 as result
  console.log(result); // 1
  return result * 2; // 100 * 2. result = 200 
}).then(function(result) { // (***) // recieve 200 as result
  console.log(result); // 2
  return result * 2; // 200 * 2. result = 400 
}).then(function(result) { // recieve 400 as result
  console.log(result); // 4
  return result * 2; // 400 * 2. result = 800 
});
// 100
// 200
// 400
```

```js
async function f() {
  let promise = new Promise((resolve, reject) => {
    setTimeout(() => resolve("done!"), 1000)
  });
  let result = await promise; // wait until the promise resolves (*)
  console.log(result); // "done!"
}

f();

async function f() {
  let promise = new Promise((resolve, reject) => {
    setTimeout(() => resolve("done!"), 3000)
  });
  let result = await promise; // it waits until promise is resolved (*)
  console.log(result); // "done!"
    return 100
}
f().then(function(result) { // (**)
  console.log(result); // 1
  return result * 2;
}).then(function(result) { // (***)
  console.log(result); // 2
  return result * 2;
}).then(function(result) {
  console.log(result); // 4
  return result * 2;
});
// 100
// 200
// 400
```


#Event loop

[Great video to watch to understand Event loop and asynchronous JavaScript](https://www.youtube.com/watch?v=8aGhZQkoFbQ&feature=emb_title)

## call stack / stack
JavaScript has single thread runtime which means it has a **single call stack**. So <u>it can do one that at a time</u>.
and stack is like haystack. A horse will start eating what's on the bottom. For stacks, the **latest pushed item is received first**, that’s also called LIFO (**_Last-In-First-Out_**) principle.

You can implement this by using push and pop with Array/Object. The push method will add any object to the top of the stack and the pop method will remove it.


# Queue
For queues, we have FIFO (First-In-First-Out).
A queue is one of the most common uses of an array.
**enqueue**—This operation is responsible for inserting or pushing a new element to the queue.
**dequeue**—This operation is responsible for removing the oldest element from the queue.
At some point during the event loop, the runtime starts handling the messages on the queue, starting with the oldest one. To do so, the message is removed from the queue and its corresponding function is called with the message as an input parameter. As always, calling a function creates a new stack frame for that function's use.
The processing of functions continues until the stack is once again empty. Then, the event loop will process the next message in the queue (if there is one).

##heap
Objects are allocated in a heap which is just a name to denote a large (mostly unstructured) region of memory.

[Event loop -mdn](https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop)