티스토리 뷰

hoisting


var 변수 선언과 함수 선언문에서 발생한다.

함수 내에서 아랫쪽에 존재하는 내용 중 필요한 값들을 최상단으로 끌어올린다.

실제로 코드가 올라가는 것이 아니고, JavaScript 내부적으로 끌어올려서 처리하는 것이다.

따라서 실제 메모리에서의 변화도 없다.

var의 할당과 함수 표현식은 hoisting되지 않는다.

var foo; // var의 선언
function foo2() { console.log('hello'); } // 함수 선언문

var foo = 'hello'; // var의 할당
var foo2 = function() { console.log('hello'); } // 함수 표현식

 

 

콜백 함수


함수가 끝나고 난 뒤에 인자로 전달되어 실행되는 함수

 

 

 

콜백(setTimeout)을 이용한 비동기 처리


function printWithDelay(print, timeout) {
    setTimeout(print, timeout);
}

printWithDelay(() => console.log('async callback'), 2000);

Promise를 이용한 비동기 처리


  1. 상태 - 성공했는지 실패했는지
  2. producer - consumer의 견해 차이

 

state : 수행 중일 때 pendingfulfilled or rejected 

 

  1. producer : Promise object
const promise = new Promise((resolve, reject) => {
    // doing some heavy work (network, read files)
    console.log('doing something...');
    setTimeout(() => {
        resolve('hello');
    }, 2000);
});

새로운 Promise 객체가 생성될 때, executor는 자동 생성된다.

 

  1. consumer : then, catch, finally
promise
    .then(value => {
        console.log(value);
    })
    .catch(error => {
        console.log(error);
    })
    .finally(() => {
        console.log('finally');
    });

then - 정상일 때 수행

catch - error 발생 시 수행

finally - 무조건 수행

 

 

  1. Promise chaining
const fetchNumber = new Promise((resolve, reject) => {
    setTimeout(() => resolve(1), 1000);
});

fetchNubmer
.then(num => num * 2)
.then(num => num * 3)
.then(num => {
    return new Promise((resolve, reject) => {
        setTimeout(() => resolve(num - 1), 1000);
    });
})

then을 chaining하여 then에서 반환된 값을 chaining된 다음 then으로 전달 가능

 

 

  1. Error Handling
const getHen = () =>
    new Promise((resolve, reject) => {
        setTimeout(() => resolve('🐓'), 1000);
    });

const getEgg = () =>
    new Promise((resolve, reject) => {
        setTimeout(() => resolve(`${hen} => 🥚`, 1000);
    });

const cook = () =>
    new Promise((resolve, reject) => {
        setTimeout(() => resolve(`${egg) => 🍳`, 1000);
    });

getHen()
    .then(hen => getEgg(hen))
    .catch(error => {
        return '🍗';
    })
    .then(egg => cook(egg))
    .then(meal => console.log(meal))
    .catch(console.log);

// getHen().then(getEgg).then(cook).then(console.log);

// 🐓 => 🥚 => 🍳

chaining되어 있어도 then, catch를 연속으로 연결시키면

성공했을 때는 then, 실패했을 때는 catch를 수행하게 된다.

error 발생을 고려하여 항상 error handler(catch)를 설정해주어야 한다.

 

 

async - await


Promise 객체를 chaining하면 복잡해진다.

깔끔하게 Promise를 사용하는 방법이 async - await이다.

따라서 async - await를 이용하여 동기식으로(순서대로) 코드를 작성하지만 비동기로 작동되게 한다.

function fetchUser() {
    // do network request in 10 secs....
    return 'hello'; // Promise 객체로 반환
}

const user = fetchUser();
console.log(user);

fetchUser()가 10초 걸리기 때문에 뒤에 나오는 코드들은 10초 후에 실행된다.

따라서 이 문제를 해결하고자 비동기 처리를 해준다.

비동기 처리를 해주기 위해 fetchUser()Promise 객체를 반환하게 바꾼다.

function fetchUser() {
    return new Promise((resolve, reject) => {
        // do network request in 10 secs....
        resolve('hello');
    });
}

const user = fetchUser();
user.then(console.log);
console.log(user);

Promise를 이용하지 않고 간단하게 비동기를 사용하려면 async 사용

async function fetchUser() {
    // do network request in 10 secs....
    return 'hello'; // Promise 객체로 반환
}

const user = fetchUser();
user.then(console.log);
console.log(user);

await의 사용


async 함수 안에서 사용한다.

await이 끝날때까지 기다려준다.

function delay(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

async function getApple() {
    await delay(3000); // 3초 후 아래 코드 실행
    return '🍎';
}

async function getBanana() {
    await delay(3000);
    return '🍌';
}

다음과 같이 Promise를 많이 chaining하게 되면 콜백 지옥처럼 복잡해진다.

function pickFruits() {
    return getApple()
    .then(apple => {
        return getBanana()
        .then(banana => `${apple} + ${banana}`);
    });
}

pickFruits().then(console.log);

async를 활용하여 간단하게 바꿔주면 다음과 같다.

async function pickFruits() {
    const apple = await getApple();
    const banana = await getBanana();
    return `${apple} + ${banana}`;
}

pickFruits().then(console.log);

동기적으로 사용할 수 있고 return도 자연스러워졌다.

async - await에서는 try - catch문을 활용하여 error handling을 해준다.

하지만 getApple()이 끝나고 getBanana()가 실행되기 때문에 비효율적이다. (이 때, 서로 연관이 없다고 가정)

async function pickFruits() {
    const applePromise = getApple(); // 이 때 바로 실행
    const bananaPromise = getBanana(); // 이 때 바로 실행
    const apple = await applePromise;
    const banan = await bananaPromise;
    return `${apple} + ${banana}`;
}

pickFruits().then(console.log);

이렇게 하면 await의 병렬처리가 가능해지지만 이것도 역시 비효율적이다.

그래서 Promise APIall()을 활용해준다.

인자로 들어오는 Promise 객체 배열이 모두 종료된 후 then()으로 전달된다.

function pickAllFruits() {
    return Promise.all([getApple(), getBanana()])
    .then(fruits => fruits.join(' + '));
}

pickAllFruits().then(console.log);

race()는 인자로 들어오는 Promise 객체 배열 중 가장 먼저 종료된 것을 then()으로 전달해준다.

function pickOnlyOne() {
    return Promise.race([getApple(), getBanana()]);
}

    pickOnlyOne().then(console.log); // getApple()과 getBanana() 중 먼저 끝나는 것 반환

 

 

 

 

 

출처

자바스크립트 11. 비동기 처리의 시작 콜백 이해하기, 콜백 지옥 체험 😱 JavaScript Callback | 프론트엔드 개발자 입문편 (JavaScript ES6)

'JavaScript' 카테고리의 다른 글

[JavaScript] DOM API  (0) 2020.10.11
[JavaScript] JSON  (0) 2020.10.05
[JavaScript] 고차 함수(Higher-Order Function)  (1) 2020.10.01
[JavaScript] 1급 시민, 1급 객체  (0) 2020.09.30
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함