[JS/Node] 비동기

정지우·2021년 6월 23일
0

keyword.zip

목록 보기
23/40

iterator

콜백 함수

다른 함수(A)의 전달인자로 넘겨주는 함수(B)

function B() {
  console.log("called at the back!");
}
function A(Callback) {
  callback(); // callback === B
}

A(B);

함수 A는 함수 B(콜백함수)를 동기적으로 또는 비동기적으로 실행할 수 있다.

상황 별 콜백함수

1) 반복 실행하는 함수(iterator)

예) for each, map, filter 메소드 등

[1, 2, 3].map((element, index) => {
	return element* element;
});

2) 이벤트에 따른 함수(event handler)

document.querySelector('#btn').addEventListener('click', (e) => { 
  console.log('button clicked'); 
});

콜백함수 주의사항

콜백함수는 함수 자체를 연결하는 것이지, 함수 실행을 연결하는 것이 아니다.

function handleClick() {
  console.log('button clicked');
}

/*함수 자체를 연결하는 옳은 예*/
document.querySelector('#btn').onclick = handleClick; // (o)
document.querySelector('#btn').onclick = () => {handleClick();} // (o)
document.querySelector('#btn').onclick = handleClick.bind(); // (o)

/*함수 실행을 연결하는 잘못된 예*/
document.querySelector('#btn').onclick = handleClick(); // (o)

handleClick(); // handleClick의 실행 결과 === 'undefined'
	       // return 값이 없기 때문이다.
               // 따라서, 마지막 코드는 onclick에 'undefined'를 연결한 것과 마찬가지가 된다. 

blocking

blocking === 전화
전화를 받으려면 하던 작업을 멈추어야 한다.
요청(착신)에 대한 결과(수신)가 동시에 일어난다.

non-blocking

non-blocking === 문자
요청에 대한 결과가 동시에 일어나지 않는다.
비동기적으로 일어난다.

손님이 아메리카노를 주문한다. === "요청"

"요청"에 blocking이 없다.
"응답"이 비동기적으로 이루어진다.

아메리카노가 완성되면 직원이 손님을 부른다.

완성되면 === "이벤트"

아메리카노가 완성되면 직원이 손님을 부른다.

손님을 부른다 === "이벤트 핸들러" === "콜백함수"

동기적 코드

function waitSync(ms){
    var start = Date.now();
    var now = start;
    while(now - start < ms) {
        now = Date.now();
    }
} // 현재 시각과 시작 시각을 비교하며 ms 범위 내에서 무한 루프를 도는 blocking 함수입니다.

function drink(person, coffee){
    console.log(person + '는 '+ coffee + '를 마십니다');
}

function orderCoffeeSync(coffee){
    console.log(coffee + '가 접수되었습니다');
    waitSync(4000);
    return coffee;
}

let customers = [{
    name: 'Steve',
    request: '카페라떼'
}, {
    name: 'John',
    request: '아메리카노'
}];

// call synchronously
customers.forEach(function(customer) {
    let coffee = orderCoffeeSync(customer.request);
drink(customer.name, coffee);
});

비동기적 코드

function waitAsync(callback, ms){
    setTimeout(callback, ms);
    // 특정 시간 이후에 callback함수가 실행되게금 하는 브라우저 내장 긴능입니다.
}

function drink(person, coffee) {
    console.log(person + '는 ' + coffee + '를 마십니다');
}

function orderCoffeeSync(coffee) {
    console.log(coffee + '가 접수되었습니다');
    waitSync(2000);
    return coffee;
}

let customers = [{
    name: 'Steve',
    request: '카페라떼'
}, {
    name: 'Jhon',
    request: '아메리카노'
}];

function orderCoffeeAsync(menu, callback){
    console.log(menu + '가 접수되었습니다');
    waitAsync(function() {
        callback(menu);
    }, 2000);
}

// call asynchronously
customers.forEach(function(customer) {
    orderCoffeeAsync(customer.request, function(coffee) {
    drink(customer.name, coffee);
    });
});

비동기 주요 사례

서버에 자원 요청 및 응답
1. fetch API - 서버에 요청하기
2. AJAX(XHR)

'비동기적'이기 때문에, 로딩이 이루어진다고 하지만, 다른 컴포넌트를 조작할 수 있다.

비동기 원리 알아보기 - Event loop

event loop

async

자바스크립트가 돌아가는 원리 === '비동기'
문제점 : 순서를 제어할 수 없다.

const printString = (string) => {
    setTimeout( () => {
        console.log(string);
    },
    Math.floor(Math.random() * 100) + 1
    )
}

const printAll = () => {
    printString("A")
    printString("B")
    printString("C")
}
printAll(); // what do you expect? Random

callback함수

비동기의 순서를 제어하기 위해서 필요하다.

const printString = (string, callback) => {
    setTimeout( () => {
        console.log(string);
        callback();
    },
    Math.floor(Math.random() * 100) + 1
    )
}

const printAll = () => {
    printString("A", () => {
        printString("B", () => {
            printString("C", () => {})
        })
    })
}    
printAll(); // now, what do you expect? A, B, C

문제점: callback hell이 일어난다.(복잡해짐)

promise

resolve()와 reject() 명령어를 통해 다음 action으로 넘어가거나, error를 handle할 수 있다.
첫 task가 끝나면 .then()을 통해 다음 task를 이어서 진행할 수 있다.
콜백함수와 달리, error처리를 하는 경우,
마지막 chain에서만 .catch()를 통해 error처리를 해줄 수 있다.

const printString = (string) => {
    return new Promise((resolve, reject) => {
    setTimeout(
        () => {
            console.log(string);
            resolve();
        },
        Math.floor(Math.random() * 100) + 1
    )
    
})
}
                       
                       
const printAll = () => {
    printString("A")
    .then(() => {
        return printString("B")
    })
    .then( () => {
        return printString("C")
    })
}    
printAll(); // now, what do you expect?

callback과 동일하게 동작하지만, 가독성을 높여주는 것을 알 수 있다.
문제점: promise hell 발생

function gotoCodestates() {
    return new Promise((resolve, reject) => {
    setTimeout( () => { resolve('1. go to codestates') }, 100)
    })
}

function sitAndCode() {
    return new Promise((resolve, reject) => {
    setTimeout( () => { resolve('2. sit and code') }, 100)
    })
}

function eatLunch() {
    return new Promise((resolve, reject) => {
    setTimeout( () => { resolve('3. eat lunch') }, 100)
    })
}

function goToBed() {
    return new Promise((resolve, reject) => {
    setTimeout( () => { resolve('4. goToBed') }, 100)
    })
}

gotoCodestates()
.then(data => {
    console.log(data);

    sitAndCode()
    .then(data => {
        console.log(data)
    
        eatLunch()
        .then(data => {
            console.log(data);
        
            goToBed()
            .then(data => {
                console.log(data)
            })
        })
    })
})

promise Chaining

function gotoCodestates() {
    return new Promise((resolve, reject) => {
    setTimeout( () => { resolve('1. go to codestates') }, 100)
    })
}

function gotoCodestates() {
    return new Promise((resolve, reject) => {
    setTimeout( () => { resolve('1. go to codestates') }, 100)
    })
}

function sitAndCode() {
    return new Promise((resolve, reject) => {
    setTimeout( () => { resolve('2. sit and code') }, 100)
    })
}

function eatLunch() {
    return new Promise((resolve, reject) => {
    setTimeout( () => { resolve('3. eat lunch') }, 100)
    })
}

function goToBed() {
    return new Promise((resolve, reject) => {
    setTimeout( () => { resolve('4. goToBed') }, 100)
    })
}

gotoCodestates()
.then(data => {
    console.log(data);
    return sitAndCode()
})
.then(data => {
    console.log(data);
    return eatLunch();
})
.then(data => {
    console.log(data);
    return goToBed();
})
.then(data => {
    console.log(data);
})

async await

promise화된 함수들에 대하여,
resultasync 함수로 만들어 주고
await을 사용하여, 비동기 함수들을 동기 함수처럼 사용할 수 있다.
promise 일종이지만, promise 함수 보다, 훨씬 코드 가독성이 높아진다.

function gotoCodestates() {
    return new Promise((resolve, reject) => {
    setTimeout( () => { resolve('1. go to codestates') }, 100)
    })
}

function gotoCodestates() {
    return new Promise((resolve, reject) => {
    setTimeout( () => { resolve('1. go to codestates') }, 100)
    })
}

function sitAndCode() {
    return new Promise((resolve, reject) => {
    setTimeout( () => { resolve('2. sit and code') }, 100)
    })
}

function eatLunch() {
    return new Promise((resolve, reject) => {
    setTimeout( () => { resolve('3. eat lunch') }, 100)
    })
}

function goToBed() {
    return new Promise((resolve, reject) => {
    setTimeout( () => { resolve('4. goToBed') }, 100)
    })
}

const result = async() => {
    const one = await gotoCodestates();
    console.log(one);

    const two = await sitAndCode();
    console.log(two);

    const three = await eatLunch();
    console.log(three);

    const four = await goToBed();
    console.log(four);
}

result();

Promise.all() 메서드

순회 가능한 객체에 주어진 모든 프로미스가 이행한 후, 혹은 프로미스가 주어지지 않았을 때 이행하는 Promise를 반환한다.
반환 형태는 '배열'
주어진 프로미스 중 하나가 거부하는 경우, 첫 번째로 거절한 프로미스의 이유를 사용해 자신도 거부합니다.

profile
재미를 쫓는 개발자

0개의 댓글