코드스테이츠 수업 25일차!
비동기 뜻은 이해하지만 내용이 어렵다
정확한 개념인지를 위해 복습하자 복습복습복습!!
동기
특정 코드의 실행이 완료될 때까지 기다리고 난 후 다음 코드를 수행하는 것
비동기
특정 코드의 실행이 완료될 때까지 기다리지 않고 다음 코드들을 수행하는 것
- 비동기는 주로 콜백함수를 활용하는 것이 특징
JavaScript의 작동원리
싱글 스레드 기반으로 동작하는 언어 -> 동기적으로 작동함
하지만 런타임에서 비동기 처리를 동와주기 때문에 비동기 처리 가능
타이머 관련 API
setTimeout(callback, millisecond)
일정 시간 후에 함수를 실행
// 매개변수 : 실행할 콜백 함수, 콜백 함수 실행 전 기다려야 할 시간 (밀리초)
// return 값 : 임의의 타이머 ID
setTimeout(function(){
console.log('1초 후 실행');
}, 1000);
clearTimeout(timerId)
setTimeout 타이머를 종료
// 매개변수 : 타이머 ID
// return 값 : 없음
const timer = setTimeout(function(){
console.log('10초 후 실행');
}, 10000);
clearTimeout(timer);
setInterval(callback, millisecond)
일정 시간의 간격을 가지고 함수를 반복적으로 실행
// 매개변수 : 실행할 콜백 함수, 반복적으로 함수를 실행시키기 위한 시간 간격 (밀리초)
// return 값 : 임의의 타이머 ID
setInterval(function(){
console.log('1초마다 실행');
}, 1000);
clearInterval(timerId)
setInterval 타이머를 종료
// 매개변수 : 타이머 ID
// return 값 : 없음
const timer = setInterval(function(){
console.log('1초마다 실행');
}, 1000);
clearInterval(timer);
Callback 함수 활용
예측 가능한 코드 작성을 위해 비동기로 작동하는 코드를 제어할 수 있는 방법에 대해 알고있어야 한다
여러 방법 중 하나는 Callback 함수를 활용하는 방법이다
-> 비동기 코드의 순서를 제어할 수 있다
Callback Hell
Callback 함수를 통해 비동기 코드의 순서를 제어할 수 있지만 코드가 길어질수록 복잡해지고 가독성이 낮아진다
Promise
new Promise
Promise는 class이기 때문에 new 키워드를 통해 Promise 객체를 생성한다
let promise = new Promise((resolve, reject) => {
// 정상적으로 처리되는 경우
// resolve의 인자에 값을 전달할 수 있음
resolve(value);
// 에러가 발생하는 경우
// reject의 인자에 에러메세지를 전달할 수 있음
reject(error);
});
Promise 객체의 내부 프로퍼티
new Promise가 반환하는 Promise 객체는 state, result 내부 프로퍼티를 갖는다
하지만 직접 접근할 수 없고 .then, .catch, .finally의 메서드를 사용해야 접근이 가능하다
Promise의 3가지 상태
pending : 비동기 처리가 아직 수행되지 않은 상태 -> 프로미스가 생성된 직후 기본 상태
fulfilled : 비동기 처리가 수행된 상태(성공) -> resolve 함수 호출
rejected : 비동기 처리가 수행된 상태(실패) -> reject 함수 호출
state
기본 상태는 pending(대기)
비동기 처리를 수행할 콜백 함수가 성공적으로 작동했다면 fulfilled(이행)로 변경이 되고, 에러가 발생했다면 rejected(거부)가 된다
result
처음은 undefined
비동기 처리를 수행할 콜백 함수가 성공적으로 작동하여 resolve(value)가 호출되면 value로,
에러가 발생하여 reject(error)가 호출되면 error로 변한다
then
두 개의 콜백 함수를 인수로 전달받는다
- 첫 번째 콜백 함수는 프로미스가 fulfilled 상태가 되면 호출된다. 이때 콜백 함수는 프로미스의 비동기 처리 결과를 인수로 전달받는다
- 두 번째 콜백 함수는 프로미스가 rejected 상태가 되면 호출된다. 이때 콜백 함수는 프로미스의 에러를 인수로 전달받는다
첫 번째 콜백 함수는 비동기 처리가 성공했을 때 호출되는 성공 처리 콜백 함수
두 번째 콜백 함수는 비동기 처리가 실패했을 때 호출되는 실패 처리 콜백 함수
// fulfilled
new Promise(resolve =>('fulfilled'))
.then(v => console.log(v), e => console.error(e)); // fulfilled
// rejected
new Promise((_, reject) => reject(new Error('rejected')))
.then(v => console.log(v), e => console.error(e)); // Error: rejected
const promise = new Promise((resolve, reject)=>{
setTimeout(()=>{
resolve("성공");
}, 1000);
});
promise.then(value => console.log(value));
// 1초 후에 결과가 출력
// 성공
then 메서드는 언제나 프로미스를 반환
만얀 then 메서드의 콜백 함수가 프로미스를 반환하면 그 프로미스를 그대로 반환하고,
프로미스가 아닌 값을 반환하면 그 값을 암묵적으로 resolve 또는 reject하여 프로미스를 생성해 반환
catch
한 개의 콜백 함수를 인수로 전달받는다
catch 메서드의 콜백 함수는 프로미스가 rejected 상태인 경우만 호출
-> executor에 작성했던 코드들이 에러가 발생했을 경우에는 reject 함수를 호출하고 .catch 메서드로 접근 가능
// catch 메서드는 then(undefined, onRejected)과 동일하게 동작
// rejected
new Promise((_, reject) => reject(new Error('rejected')))
.catch(e => console.log(e)); // Error: rejected
// rejected
new Promise((_, reject) => reject(new Error('rejected')))
.then(undefined, e => console.log(e)); // Error: rejected
let promise = new Promise(function(resolve, reject){
reject(new Error("에러"))
});
promise.catch(error => {
console.log(error);
// Error: 에러
})
finally
executor에 작성했던 코드들의 정상 처리 여부와 상관없이 .finally 메서드로 접근 가능
let promise = new Promise(function(resolve, reject){
resolve('성공');
});
promise
.then(value => {
console.log(value);
// '성공'
})
.catch(error => {
console.log(error);
})
.finally(() => {
console.log('성공이든 실패든 작동!');
// '성공이든 실패든 작동!'
})
Promise chaining
비동기 작업을 순차적으로 진행해야 하는 경우 필요
promise chaining이 가능한 이유는 .then, .catch, .finally의 메서드들은 Promise를 리턴하기 때문
.then을 통해 연결할 수 있고, 에러가 발생할 경우 .catch로 처리하면 된다
let promise = new Promise(function(resolve, reject) {
resolve('성공');
...
});
promise
.then((value) => {
console.log(value);
return '성공';
})
.then((value) => {
console.log(value);
return '성공';
})
.then((value) => {
console.log(value);
return '성공';
})
.catch((error) => {
console.log(error);
return '실패';
})
.finally(() => {
console.log('성공이든 실패든 작동!');
});
Promise.all()
여러 개의 비동기 작업을 동시에 처리하고 싶을 때 사용
인자로는 배열을 받습니다. 해당 배열에 있는 모든 Promise에서 executor 내 작성했던 코드들이 정상적으로 처리가 되었다면 결과를 배열에 저장해 새로운 Promise를 반환해줍니다.
const promiseOne = () => new Promise((resolve, reject) => setTimeout(() => resolve('1초'), 1000));
const promiseTwo = () => new Promise((resolve, reject) => setTimeout(() => resolve('2초'), 2000));
const promiseThree = () => new Promise((resolve, reject) => setTimeout(() => resolve('3초'), 3000));
Promise.all([promiseOne(), promiseTwo(), promiseThree()])
.then((value) => console.log(value))
// ['1초', '2초', '3초']
.catch((err) => console.log(err));
인자로 받는 배열에 있는 Promise 중 하나라도 에러가 발생하게 되면 나머지 Promise의 state와 상관없이 즉시 종료
Promise Hell
Promise를 통해 비동기 코드의 순서를 제어할 수 있지만 Callback 함수와 같이 코드가 길어질수록 복잡해지고 가독성이 낮아지는 Promise Hell이 발생하는 단점이 있습니다
Async / Await
함수 앞에 async 키워드를 사용하고 async 함수 내에서만 await 키워드를 사용하면 됩니다.
이렇게 작성된 코드는 await 키워드가 작성된 코드가 동작하고 나서야 다음 순서의 코드가 동작하게 됩니다.
//지아님이 설명해주신 것
[참고 : async/await 정의]
* async(await식이 포함)
->함수의 실행을 일시 중지하고 전달된 promise의 해결이 된 다음에 async함수의 실행을 다시 시작하고 완료 후 반환함
* await(async안에서만 유효)
->Promise가 fulfill되거나 reject될때까지 async 함수의 실행을 일시정지 → Promise가 reject되면 await문은 reject된 값을 throw함
2. await 키워드 다음에 등장하는 함수 실행은, 어떤 타입을 리턴할 경우에만 의미가 있나요?
-> Promise타입을 리턴한 경우에만 의미가 있음!
3. await 키워드를 사용할 경우, 어떤 값이 리턴되나요?
-> Promise에서 fulfill된 값 (= 콜백함수가 성공적으로 완료된 경우)
'CodeStates > JavaScript' 카테고리의 다른 글
Section2 / Unit3 : fetch API, axios (0) | 2023.05.17 |
---|---|
Section2 / Unit3 : Node.js (0) | 2023.05.16 |
Section2 / Unit2 : JS 객체 지향 프로그래밍 복습 (0) | 2023.05.12 |
Section2 / Unit2 : 프로토타입 체인 (0) | 2023.05.11 |
Section2 / Unit2 : 프로토타입과 클래스 (0) | 2023.05.11 |