DEV Community

Dahye Ji
Dahye Ji

Posted on

Try...catch, Asynchronous JavaScript - promise, async, await, event loop ...

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

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
Enter fullscreen mode Exit fullscreen mode

More about destructuring assignment -javascript.info

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.

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) <--
}
Enter fullscreen mode Exit fullscreen mode

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.

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)
}


Enter fullscreen mode Exit fullscreen mode

JavaScript has many built-in constructors for standard errors: Error, SyntaxError, ReferenceError, TypeError and others.

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!
Enter fullscreen mode Exit fullscreen mode
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
}
Enter fullscreen mode Exit fullscreen mode

try...catch...finally

If finally exists, in runs always no matter what.

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');
}
Enter fullscreen mode Exit fullscreen mode

How to use try...catch

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. (**)
  }
}
Enter fullscreen mode Exit fullscreen mode

More about try..catch -javascript.info

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.
// 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);
Enter fullscreen mode Exit fullscreen mode

promise1
As you can see above, Promise {} became Promise {: 'done'} after 1000ms.

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!
Enter fullscreen mode Exit fullscreen mode
new Promise((resolve, reject) => {...code...})
  .then(...code...)
  .then(...code...)
  .finally(...code...)
  .catch(...code...); // <-- can handle error at .catch
Enter fullscreen mode Exit fullscreen mode
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
Enter fullscreen mode Exit fullscreen mode

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.

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!
Enter fullscreen mode Exit fullscreen mode

Promise - finally

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
Enter fullscreen mode Exit fullscreen mode

About Promise -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.

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
    })
Enter fullscreen mode Exit fullscreen mode

About fetch

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 asynchronous, promise-based behavior to be written in a cleaner style, avoiding the need to explicitly configure promise chains.

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
Enter fullscreen mode Exit fullscreen mode
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
Enter fullscreen mode Exit fullscreen mode

Event loop

Great video to watch to understand Event loop and asynchronous JavaScript

call stack / stack

JavaScript has single thread runtime which means it has a single call stack. So it can do one that at a time.
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

Discussion (0)