자바스크립트를 처음 배울 때, 표준 내장 객체를 이용해 코드를 간단히 작성할 수 있다는 점이 매우 신기했다. 반복문이나 조건문을 통해 힘들게 로직을 구성하지 않아도 데이터를 원하는 대로 가공할 수 있었기 때문이다. 마치 마법 같았다. 하지만 콜백 함수를 넘겨주는 방식에 익숙하지 않고, 메소드마다 반환값이 달라서 생소하고 어려운 것도 사실이었다. 그래도 오늘 수업을 통해 조금 더 익숙해 졌다. 특히 메소드 체이닝을 많이 연습할 수 있어서 유익한 시간이었다. 또, reduce
를 이용한 연습 문제 풀이가 마음에 든다.
//6. 남학생들의 평균 연령 구하기
const maleTotalInfo = students.reduce(
(accumulator, currentValue) => {
if (currentValue.gender === 'male') {
accumulator.maleTotalAge += currentValue.age;
accumulator.maleTotalNum += 1;
}
return accumulator;
},
{ maleTotalAge: 0, maleTotalNum: 0 }
);
const maleAverageAge = maleTotalInfo.maleTotalAge / maleTotalInfo.maleTotalNum;
console.log(maleAverageAge);
비동기를 처리하는 방법으로는 콜백 함수, Promise, async/await가 있다는 사실을 알고 있었지만, 자세히 설명할 자신은 없었다. 특히 Promise는 다시 공부해야겠다는 생각이 들 정도로 어려웠다. 사실 오늘도 완벽히 이해했다고 말하기는 어려울 것 같다. 집에 돌아오는 지하철에서 관련 동영상을 여러 개 보았지만, 여전히 부족한 느낌이었다. 대신, 조금 더 익숙해진 것은 사실이다. 이제 콜백 지옥에 대해서는 코드 예시를 통해 설명할 수 있을 것 같다. 오늘 특히 좋았던 부분은 콜백 지옥 코드를 Promise와 async/await를 이용해서 개선해보는 시간이었다.
function Shape(color) {
this.color = color;
this.getColor = function () {
return `이 도형의 색상은 ${this.color}입니다.`;
};
}
const shape1 = new Shape('red');
function Rectangle(color, width, height) {
Shape.call(this, color); // Shape를 상속받게 하기
this.color = color;
this.width = width;
this.height = height;
this.getArea = function () {
return this.width * this.height;
};
}
const rect1 = new Rectangle('blue', 20, 20);
console.log(shape1);
class Shape {
constructor(color) {
this.color = color;
}
getColor() {
return `이 도형의 색상은 ${this.color}입니다.`;
}
}
const shape1 = new Shape('red');
class Rectangle extends Shape { // Shape 상속
constructor(color, width, height) {
super(color);
this.width = width;
this.height = height;
}
getArea() {
return this.width * this.height;
}
}
const rect1 = new Rectangle('blue', 20, 20);
console.log(shape1);
console.dir(rect1);
shap1
객체의 메소드 getColor
가 프로토타입 내부에 존재함을 알 수 있음rect1
객체는 Shape
를 상속 받아서 프로토타입의 프로토타입의 constructor
가 class Shape
이며 getColor
도 여기 존재함을 알 수 있음<콘솔에 출력된 결과 (생상자 함수shape1
/ 클래스 shape1
/ 클래스 rect1
)>
Setter 메서드는 클래스의 특정 속성에 값을 설정할 때 사용자 정의 검사를 수행할 수 있게 함
Car
클래스에서 speed
속성을 설정할 때 음수 값을 허용하지 않도록 검사하는 setter
를 정의함class Car {
constructor(speed) {
this.speed = speed;
}
set speed(speed) {
if (speed < 0) {
throw new Error('속도는 음수가 될 수 없습니다.');
}
this._speed = speed; // 내부 속성에 저장
}
getSpeed() {
return `현재 속도는 ${this._speed}입니다.`;
}
}
const car1 = new Car(100);
console.log(car1.getSpeed()); // 현재 속도는 100입니다.
this.speed = speed
를 this._speed = speed
로 변경하여 이를 해결함Getter 메서드는 속성 값을 참조할 때 사용됨
Car
클래스의 예제에서는 speed
속성을 안전하게 참조할 수 있도록 getter를 추가함class Car {
constructor(speed) {
this.speed = speed;
}
set speed(speed) {
if (speed < 0) {
throw new Error('속도는 음수가 될 수 없습니다.');
}
this._speed = speed;
}
get speed() {
return this._speed;
}
getSpeed() {
return `현재 속도는 ${this.speed}입니다.`;
}
}
const car1 = new Car(100);
console.log(car1.getSpeed()); // 현재 속도는 100입니다.
클래스 내에서만 접근 가능한 속성을 정의할 때는 #
기호를 사용하여 private 속성을 만듦, 따라서 setter
와 양립할 수 없음
class Car {
#name; // private 속성
constructor(name, speed) {
this.#name = name;
this.speed = speed;
}
set speed(speed) {
if (speed < 0) {
throw new Error('속도는 음수가 될 수 없습니다.');
}
this._speed = speed;
}
get speed() {
return this._speed;
}
get name() {
return this.#name; // private 속성 접근에 이런 식으로 접근 해도 값을 바꿀 수 없음
}
getCarName() {
return `차 이름은 ${this.#name}입니다.`;
}
get getSpeed() {
return `현재 속도는 ${this.speed}입니다.`;
}
}
const car1 = new Car('벤츠', 100);
car1.name = '아우디'; // private 속성은 외부에서 변경되지 않음
console.log(car1.getCarName()); // 차 이름은 벤츠입니다.
정적 메서드와 속성은 클래스 자체에 속하며 멤버 속성이나 프로토타입 속성에 포함되지 않으므로 인스턴스가 아닌 클래스 이름으로 호출해야 함
class Car {
#name; // private 속성
static CREATED = '2022';
constructor(name, speed) {
this.#name = name;
this.speed = speed;
}
set speed(speed) {
if (speed < 0) {
throw new Error('속도는 음수가 될 수 없습니다.');
}
this._speed = speed;
}
get speed() {
return this._speed;
}
get name() {
return this.#name;
}
getCarName() {
return `차 이름은 ${this.#name}입니다.`;
}
get getSpeed() {
return `현재 속도는 ${this.speed}입니다.`;
}
// 정적 메서드
static getSpec() {
return `차는 타이어 4개와 문 4개가 있습니다.`;
}
}
const car1 = new Car('벤츠', 100);
console.log(Car.getSpec()); // 차는 타이어 4개와 문 4개가 있습니다.
console.log(Car.CREATED); // 2022
console.log(car1.getSpec());
Math
객체에는 정적 메서드와 속성만이 포함되어 있음console.log(Math.PI); // Math 객체의 정적 속성
console.log(Math.max(1, 2, 3)); // Math 객체의 정적 메서드
자바스크립트 엔진에 기본으로 내장되어 있는 객체들은 자바스크립트 엔진이 상시적으로 제공하는 기능으로, 어디서든 활용할 수 있음
자바스크립트에서 데이터를 생성하는 두 가지 주요 방법: 리터럴 표기법과 생성자 함수
const str = new String('Hello');
const str = "Hello";
리터럴 표기법으로 작성된 데이터가 프로토타입 객체를 사용할 수 있는 이유는 자바스크립트 엔진이 일시적으로 인스턴스 객체처럼 래핑(wrapping)하기 때문임
const str = new String('Hello');
console.dir(str);
const str2 = 'Hello';
console.dir(str2);
str2
는 기본 타입으로 저장되지만, 메서드를 호출할 때 임시로 객체로 변환됨리터럴 표기법
const str = "Hello";
생성자 함수
const str = new String('Hello');
// 리터럴 표기법
const str1 = "Hello";
console.log(str1.length); // 5
console.log(str1.toUpperCase()); // "HELLO"
// 생성자 함수
const str2 = new String('Hello');
console.log(str2.length); // 5
console.log(str2.toUpperCase()); // "HELLO"
numObject
는 객체인데 console.log(numLiteral + numObject);
가 왜 20일까?let numLiteral = 10;
let numObject = new Number(10);
console.log(numLiteral + numObject); // 20
console.log(numLiteral == numObject); // true
자바스크립트의 타입 변환 (Type Conversion)
자바스크립트는 피연산자가 서로 다른 타입일 때 자동으로 타입을 변환하는 능력이 있음
이 과정은 "암묵적 타입 변환" 또는 "타입 강제 변환"이라고 부름
객체에서 기본 값으로의 변환:
valueOf
메서드나 toString
메서드를 호출함Number
객체의 경우, valueOf
메서드가 기본 숫자 값을 반환함산술 연산:
+
, -
, *
, /
)을 수행할 때, 자바스크립트는 피연산자를 숫자로 변환하려고 시도함비교 연산:
==
연산자는 두 값을 비교할 때 타입을 강제로 변환함. numObject
는 객체이지만, 비교를 위해 valueOf
메서드를 호출하여 기본 값인 10을 얻음10 == 10
이 되어 true
를 반환함참고:
===
연산자는 타입을 변환하지 않고 비교하기 때문에,numLiteral === numObject
는false
가 됨console.log(numLiteral === numObject); // false
기본 타입(Primitive Types):
객체 타입(Object Types):
문자열의 경우:
String
객체로, 힙에 저장됨. String
객체는 래퍼 객체로, 문자열 값을 래핑하고 있으며, 추가 메서드와 프로퍼티를 제공함let strLiteral = "Hello"; // 기본 타입 문자열, 스택에 저장
let strObject = new String("Hello"); // String 객체, 힙에 저장
strLiteral
은 기본 타입 문자열로, 스택에 값이 저장됨strObject
는 String
객체로, 힙에 객체가 저장되며, 스택에는 힙에 있는 객체를 가리키는 참조(reference)가 저장됨Memory Management in JavaScript
Memory management
인스턴스 메서드를 호출했을 때, 원본 데이터가 변경되는 메서드
const arr = [1, 2, 3];
arr.push(4); // [1, 2, 3, 4]
arr.unshift(0); // [0, 1, 2, 3, 4]
arr.pop(); // [0, 1, 2, 3]
arr.shift(); // [1, 2, 3]
arr.splice(1, 1); // [1, 3] (index 1부터 1개 요소 제거)
arr.reverse(); // [3, 1]
arr.sort(); // [1, 3]
push
: 배열의 끝에 요소를 추가unshift
: 배열의 시작에 요소를 추가pop
: 배열의 끝 요소를 제거하고 반환shift
: 배열의 첫 요소를 제거하고 반환splice
: 배열의 특정 위치에 요소를 추가하거나 제거reverse
: 배열의 요소 순서를 반대로 변경sort
: 배열의 요소를 정렬이 메서드를 호출했을 때, 원본 데이터가 변경되지 않는 메서드
const arr = [1, 2, 3, 4];
const filteredArr = arr.filter(num => num > 2); // [3, 4]
const mappedArr = arr.map(num => num * 2); // [2, 4, 6, 8]
const sum = arr.reduce((acc, num) => acc + num, 0); // 10
const concatenatedArr = arr.concat([5, 6]); // [1, 2, 3, 4, 5, 6]
const slicedArr = arr.slice(1, 3); // [2, 3]
const hasSome = arr.some(num => num > 2); // true
const allAboveZero = arr.every(num => num > 0); // true
const found = arr.find(num => num === 3); // 3
const foundIndex = arr.findIndex(num => num === 3); // 2
filter
: 조건에 맞는 요소들로 새로운 배열을 만듦map
: 모든 요소에 대해 주어진 함수를 호출한 결과로 새로운 배열을 만듦reduce
: 배열을 순회하며 누산기(accumulator)를 사용해 값을 하나로 줄임concat
: 두 배열을 합쳐서 새로운 배열을 만듦slice
: 배열의 일부분을 잘라내어 새로운 배열을 만듦some
: 조건에 맞는 요소가 하나라도 있는지 여부를 확인하여 true 또는 false를 반환every
: 모든 요소가 조건에 맞는지 여부를 확인하여 true 또는 false를 반환find
: 조건에 맞는 첫 번째 요소를 반환findIndex
: 조건에 맞는 첫 번째 요소의 인덱스를 반환console.log(Math.random()); // 0과 1 사이의 난수 생성
console.log(Math.max(1, 2, 3)); // 3
console.log(Math.min(1, 2, 3)); // 1
console.log(Math.pow(2, 3)); // 8
Math.random()
: 0과 1 사이의 난수를 반환Math.max()
: 전달된 인수 중 최대값을 반환Math.min()
: 전달된 인수 중 최소값을 반환Math.pow()
: 제곱 값을 반환자바스크립트는 싱글 스레드 언어로 한 번에 하나의 작업만 처리할 수 있음을 의미하며 동기적으로 실행됨
다른 함수의 매개변수로 전달되어 그 함수가 실행되는 동안 특정 시점에 호출되는 함수
동기 콜백 함수는 즉시 실행되는 콜백 함수를 의미함
function greeting(callbackFn) {
console.log('Hello');
callbackFn();
}
function goodbye() {
console.log('goodbye');
}
greeting(goodbye);
greeting
함수는 goodbye
콜백을 즉시 실행함비동기 콜백 함수는 비동기 작업이 끝난 후 호출되는 콜백 함수를 의미함
function task1(callback) {
setTimeout(() => {
console.log('task1 시작');
callback();
}, 1000);
}
function task2() {
console.log('task2 시작');
}
task1(task2);
task1
함수는 task2
콜백을 비동기 작업이 끝난 후 실행함비동기 콜백을 연속으로 사용하면 코드가 복잡해지고 가독성이 떨어지는 "콜백 지옥"에 빠질 수 있음
function task1(callback) {
setTimeout(() => {
console.log('task1 시작');
callback();
}, 1000);
}
function task2(callback) {
setTimeout(() => {
console.log('task2 시작');
callback();
}, 1000);
}
function task3(callback) {
setTimeout(() => {
console.log('task3 시작');
callback();
}, 1000);
}
function task4(callback) {
setTimeout(() => {
console.log('task4 시작');
callback();
}, 1000);
}
task1(() => {
task2(() => {
task3(() => {
task4(() => {
console.log('모든 작업 끝');
});
});
});
});
Promise는 비동기 작업을 처리할 수 있도록 도와주는 자바스크립트 내장 객체이며 다음과 같은 세 가지 상태를 가짐:
Promise
객체를 사용하면 비동기 작업을 쉽게 관리할 수 있음 Promise
객체를 생성할 때 전달되는 콜백 함수는 즉시 실행됨resolve
또는 reject
함수를 호출하여 Promise
객체의 상태를 업데이트할 수 있음const promise = new Promise((resolve, reject) => {
console.log('doing something...'); // 콜백 함수에 있는 코드를 즉시 실행함
setTimeout(() => {
resolve('success');
}, 1000);
});
promise
.then((value) => console.log(value)) // 'success' 출력
.catch((error) => console.error(error))
.finally(() => console.log('finally'));
Promise
객체가 생성됨console.log('doing something...')
이 출력됨setTimeout
의 콜백이 실행되어 resolve('success')
가 호출됨resolve
가 호출되면 Promise
객체의 상태가 pending
에서 fulfilled
로 변경됨then
메서드 내부의 콜백 함수가 실행되어 console.log(value)
에서 'success'
가 출력됨catch
메서드는 호출되지 않으며, finally
메서드가 실행되어 console.log('finally')
가 출력됨Promise 객체는 비동기 작업의 결과를 처리하기 위해 then
, catch
, finally
메서드를 제공함
then
메서드는 Promise
가 fulfilled
상태일 때 호출됨resolve
함수의 결과 값을 받는 콜백 함수를 지정함reject
함수의 결과 값을 받는 콜백 함수를 지정할 수도 있음catch
메서드를 사용하는 것이 가독성 측면에서 더 좋음const promise = new Promise((resolve, reject) => {
const isSuccess = true;
setTimeout(() => {
isSuccess ? resolve('success') : reject(new Error('fail'));
});
});
promise
.then(
(value) => console.log(value),
(error) => console.error(error)
)
.catch((error) => console.error(error)) // 만약 에러가 발생해도 catch에서는 에러가 안 걸림
.finally(() => console.log('finally'));
console.log('hello');
catch
메서드는 Promise
가 rejected
상태일 때 호출됨reject
함수의 결과 값을 받음const promise = new Promise((resolve, reject) => {
const isSuccess = false;
setTimeout(() => {
isSuccess ? resolve('success') : reject(new Error('fail'));
}, 1000);
});
promise
.then((value) => console.log(value))
.catch((error) => console.error(error))
.finally(() => console.log('finally'));
console.log('hello');
finally
메서드는 Promise
가 완료되면 무조건 호출됨then
에서 어떤 값을 반환하면 자동으로 resolve
가 처리되므로 연속해서 resolve
를 처리할 수 있음then()
에서 에러가 발생하면 이후의 then
은 실행되지 않는 문제가 있음const fetchNumber = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
}, 1000);
});
fetchNumber
.then((num) => new Promise((resolve, reject) => resolve(num * 2))) // 2 promise resolve(2)
.then((num) => num * 3) // 6
.then((num) => num * 2) // 12
.then((num) => console.log(num))
.catch((error) => console.error(error));
catch
를 사용하여 에러 이후의 then
을 계속 실행할 수 있지만 일반적인 방법은 아님 const fetchNumber = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
}, 1000);
});
fetchNumber
.then((num) => new Promise((resolve, reject) => reject(num))) // 에러 발생
.catch((num) => num) // 에러 처리
.then((num) => num * 3) // 3
.then((num) => num * 2) // 6
.then((num) => console.log(num));
function task1() {
return new Promise((resolve) => {
setTimeout(() => {
console.log('task1 시작');
resolve();
}, 1000);
});
}
function task2() {
return new Promise((resolve) => {
setTimeout(() => {
console.log('task2 시작');
resolve();
}, 1000);
});
}
function task3() {
return new Promise((resolve) => {
setTimeout(() => {
console.log('task3 시작');
resolve();
}, 1000);
});
}
function task4() {
return new Promise((resolve) => {
setTimeout(() => {
console.log('task4 시작');
resolve();
}, 1000);
});
}
task1()
.then(() => task2())
.then(() => task3())
.then(() => task4())
.then(() => {
console.log('모든 작업 끝');
})
.catch((error) => {
console.error('에러 발생:', error);
});
async
키워드를 사용하면 함수가 항상 Promise
를 반환함async
함수 내에서 반환된 값은 자동으로 Promise.resolve
로 감싸짐async
함수 내에서 발생한 에러는 Promise.reject
로 처리됨Promise
를 사용하는 코드:const getStarIcon = () =>
new Promise((resolve) => {
resolve('⭐');
});
getStarIcon().then((star) => console.log(star));
getStarIcon
함수는 Promise
객체를 반환하며, then
메서드를 사용하여 resolve
된 값을 출력함async function example() {
throw new Error('Something went wrong');
}
example().catch((error) => console.error(error)); // Error: Something went wrong
example
함수는 에러를 던짐async
키워드를 사용하여 동일한 기능을 구현한 코드:const getStarIcon = async () => '⭐'; // 무조건 resolve()
getStarIcon().then((star) => console.log(star));
여기서 getStarIcon
함수는 async
키워드를 사용하여 자동으로 Promise
객체를 반환하며, 반환된 값은 resolve
됨. 따라서 동일하게 then
메서드를 사용하여 값을 출력할 수 있음
await
키워드는 async
함수 내부에서만 사용할 수 있음await
는 Promise
가 처리될 때까지 기다린 다음, Promise
가 처리되면 resolve
된 값을 반환함const getStarIcon = async () => setTimeout(() => '⭐', 1000); // 값이 즉시 반환되지 않음
aysyc
는 Promise
를 반환할 뿐 비동기 함수를 기다려 주지는 않음setTimeout
함수를 기다려 주지 않음setTimeout
함수는 1초 후에 '⭐'을 반환하지만 async
가 기다려 주지 않아서 undefined
를 즉시 반환함Promise
가 처리될 때까지 기다려 주는 await
가 필요함setTimeout
을 Promise
로 감싸야 함비동기 처리를 위해 await
를 사용하는 예시:
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const getStarIcon = async () => {
await delay(1000);
return '⭐'; // resolve("⭐")
};
getStarIcon().then((star) => console.log(star));
delay
함수는 Promise
를 반환하며 이 Promise는 setTimeout을 사용하여 지정된 시간(ms) 후에 resolve됨getStarIcon
함수 내부에서 await delay(1000)
는 delay
함수가 반환한 Promise
가 resolve
될 때까지 1초 동안 기다림delay
함수의 Promise
가 resolve되면 getStarIcon
함수는 ⭐
을 반환함getStarIcon().then((star) => console.log(star));
는 getStarIcon
함수가 반환한 Promise
가 resolve
될 때, 즉 ⭐
이 반환될 때 then
메서드가 실행되어 star
를 출력함async
와 await
를 사용하지 않은 경우의 콜백 지옥:const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const getStarIcon = () => delay(1000).then(() => '⭐');
const getWaveIcon = () => delay(1000).then(() => '🌊');
const getFaceIcon = () => delay(1000).then(() => '🥰');
const getAllIcon = () => {
getStarIcon().then((star) => {
getWaveIcon().then((wave) => {
getFaceIcon().then((face) => {
console.log(`${star} ${wave} ${face}`);
});
});
});
};
getAllIcon();
async
와 await
를 사용하여 콜백 지옥을 해결한 예시:const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const getStarIcon = async () => {
await delay(1000);
return '⭐';
};
const getWaveIcon = async () => {
await delay(1000);
return '🌊';
};
const getFaceIcon = async () => {
await delay(1000);
return '🥰';
};
const getAllIcon = async () => {
const star = await getStarIcon();
const wave = await getWaveIcon();
const face = await getFaceIcon();
console.log(`${star} ${wave} ${face}`);
};
getAllIcon();
async
와 await
를 사용하여 비동기 작업을 순차적으로 실행하면서도 코드의 가독성을 높임const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const task1 = async () => {
await delay(1000);
return 'task1 시작';
};
const task2 = async () => {
await delay(2000);
return 'task2 시작';
};
const task3 = async () => {
await delay(1000);
return 'task3 시작';
};
const task4 = async () => {
await delay(1000);
return 'task4 시작';
};
const startTasks = async () => {
console.time();
const msg1 = await task1();
const msg2 = await task2();
const msg3 = await task3();
const msg4 = await task4();
console.log(msg1, msg2, msg3, msg4);
console.timeEnd();
};
startTasks();
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
async function task1() {
await delay(1000);
return 'task1 시작';
}
async function task2() {
await delay(2000);
return 'task2 시작';
}
async function task3() {
await delay(1000);
return 'task3 시작';
}
async function task4() {
await delay(1000);
return 'task4 시작';
}
async function startTasks() {
console.time('병렬 실행');
const task1Promise = task1();
const task2Promise = task2();
const task3Promise = task3();
const task4Promise = task4();
const msg1 = await task1Promise;
const msg2 = await task2Promise;
const msg3 = await task3Promise;
const msg4 = await task4Promise;
console.log(msg1, msg2, msg3, msg4);
console.timeEnd('병렬 실행');
}
startTasks();
task2
가 완료되는 2초 후에 모든 작업이 완료됨Promise.all
을 사용하여 병렬로 비동기 작업을 처리할 수 있음const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
async function task1() {
await delay(1000);
return 'task1 시작';
}
async function task2() {
await delay(2000);
return 'task2 시작';
}
async function task3() {
await delay(1000);
return 'task3 시작';
}
async function task4() {
await delay(1000);
return 'task4 시작';
}
async function startTasks() {
console.time('병렬 실행');
const tasks = await Promise.all([task1(), task2(), task3(), task4()]);
console.log(tasks.join(', '));
console.timeEnd('병렬 실행');
}
startTasks();
Promise.all
을 사용하여 모든 작업을 병렬로 실행하고, 모든 작업이 완료되면 결과를 출력함Promise
중 하나라도 rejected
상태가 되면, 나머지 Promise
가 완료되지 않았더라도 Promise.all
은 즉시 rejected
상태로 변함Promise.allSettled
는 모든 Promise의 완료 여부와 상관없이 결과를 반환함Promise
의 성공과 실패를 구분하고, 각각의 결과를 처리할 수 있게 함const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
async function task1() {
await delay(1000);
return 'task1 시작';
}
async function task2() {
await delay(2000);
throw new Error('에러');
}
async function task3() {
await delay(1000);
return 'task3 시작';
}
async function task4() {
await delay(1000);
return 'task4 시작';
}
async function startTasks() {
console.time('병렬 실행');
const tasks = await Promise.allSettled([task1(), task2(), task3(), task4()]);
console.log(tasks);
console.timeEnd('병렬 실행');
}
startTasks();
Promise.allSettled
를 사용하여 모든 Promise
가 완료될 때까지 기다리며, 각 Promise
의 결과를 배열로 반환함Promise
도 포함되므로, 모든 결과를 확인할 수 있음