let todos;
const get = url => {
const xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.send();
xhr.onload = () => {
if(xhr.status === 200) {
todos = JSON.parse(xhr.response); // undefined
} else {
console.error(`${xhr.status} ${xhr.statusText}`);
}
}
};
const get = (url, successCallback, failureCallback) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.send();
xhr.onload = () => {
if(xhr.status === 200) {
// 응답에 대한 후속 처리
successCallback(JSON.parse(xhr.response));
} else {
// 에러에 대한 처리
failureCallback(xhr.status);
}
}
};
// 전형적인 콜백헬
get('/step1', a => {
get(`/step2/${a}`, b => {
get(`/step3/${b}`, c => {
get(`/step4/${c}`, d => {
console.log(d);
});
});
});
});
말이 길어서 그렇지, 대충 요약하자면, 콜백헬이 나온 이유는.
비동기 함수내의 비동기 처리 완료후 return 값으로 undefined가 뜰수 밖에 없음.
그것을 위한 예외처리를 위해 콜백을 넣었는데, 그게 콜백 처리가 너무 복잡하게 들어가면 엄청 가독성도 떨어지고 실수도 많아짐.
try {
setTimeout(() => {throw new Error('Error'); }, 1000);
} catch(e) {
// 에러를 캐치하지 못한다.
console.error('캐치한 에러', e);
}
// 프로미스 생성
const promise = new Promise((resolve, reject) => {
// Promise 함수의 콜백 함수 내부에서 비동기 처리를 수행한다.
if(/*비동기 처리 성공*/) {
resolve('reulst');
} else {
// 비동기 처리 실패
reject('failure reason');
}
});
// get 요청을 위한 비동기 함수(프로미스 이용해서 리팩토링)
const promiseGet = url => {
return new Promise((resolve, reject) => {
const xhr = XMLHttpRequest();
xhr.open('GET', url);
xhr.send();
xhr.onload = () => {
if(xhr.status === 200) {
// 성공
resolve(JSON.parse(xhr.response));
} else {
// 실패
reject(new Error(xhr.status));
}
}
});
};
// fulfilled
new Promise(resolve => 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
new Promise((_, reject) => reject(new Error('rejected')))
.catch(e => console.log(e)); // Error: rejected
new Promise(() => {})
.finally(() => console.log('finally')); // finally
// then 이용
promiseGet('https://jsonplaceholder.typicode.com/todos/1').then(
res => console.xxx(rex), // 일부러 에러 냄
err => console.error(err)
); // 두번째 콜백 함수는 첫 번째 콜배 함수에서 발생한 에러를 발견하지 못했다.
// catch 이용
promiseGet('https://jsonplaceholder.typicode.com/todos/1')
.then(res => console.log(rex)); // 일부러 에러 냄
.catch(err => console.error(err)); // TypeError
const url = 'https://jsonplaceholder.typicode.com';
promiseGet(`${url}/posts/1`)
.then(({userId}) => promiseGet(`${url}/users/${userId}`))
.then(userInfo => console.log(userInfo))
.catch(err => console.error(err));
// 배열을 resolve하는 프로미스를 생성
const resolvedPromise = Promise.resolve([1, 2, 3]);
resolvedPromise.then(console.log); // [1, 2, 3]
// 위와 같은 코드다
const resolvedPromise = new Promise((resolve) => resolve([1, 2, 3]));
resolvePromise.then(console.log); // [1, 2, 3]
// 에러 객체를 reject하는 프로미스 생성
const rejectedPromise = Promise.reject(new Error('Error!'));
rejectedPromise.catch(console.log); // Error: Error!
// 위와 같은 코드다
const rejectedPromise = new Promise((_, reject) => reject(new Error('Error!')));
rejectedPromise.catch(console.log); // Error: Error!
const requestData1 = () => new Promise(resolve => setTimeout(() => resolve(1), 3000));
const requestData2 = () => new Promise(resolve => setTimeout(() => resolve(2), 2000));
const requestData3 = () => new Promise(resolve => setTimeout(() => resolve(3), 1000));
// 3개의 비동기 처리를 병렬로 처리
Promise.all([requestData1(), requestData2(), requestData3()])
.then(console.log) // [1, 2, 3] => 약 3초
.catch(console.error);
Promise.race([
new Promise(resolve => setTimeout(() => resolve(1), 3000)),
new Promise(resolve => setTimeout(() => resolve(2), 2000)),
new Promise(resolve => setTimeout(() => resolve(3), 1000)),
])
.then(console.log) // 3
.catch(console.log);
Promise.allSettled([
new Promise(resolve => setTimeout(() => resolve(1), 2000)),
new Promise((_, reject) => setTimeout(() => reject(new Error('Error!'))))
]).then(console.log);
/*
[
{status: 'fulfilled', value: 1},
{status: 'rejected', reason: Error: Error!},
]
*/
setTimeout(() => console.log(1), 0);
Promise.resolve()
.then(() => console.log(2))
.then(() => console.log(3));
const promise = fetch(url [, options])
const request = {
get(url) {
return fetch(url);
}.
post(url, payload) {
return fetch(url, {
method: 'POST',
headers: { 'content-Type': 'application/json' },
body: JSON.stringify(payload)
});
},
patch(url(, payload) {
return fetch(url, {
method: 'PATCH',
headers: { 'content-Type': 'application/json' },
body: JSON.stringify(payload)
});
},
delete(url) {
return fetch(url, {method: 'DELETE'});
}
};
// 1. GET 요청
request.get('https://jsonplaceholder.typicode.com/todos/1')
.then(response => response.json())
.then(todos => console.log(todos))
.catch(err => console.error(err));
// 2. POST 요청
request.post('https://jsonplaceholder.typicode.com/todos/1', {
userId: 1,
title: 'JavaScript',
completed: false,
}).then(response => response.json())
.then(todos => console.log(todos))
.catch(err => console.error(err));
// 3. PATCH 요청
request.patch('https://jsonplaceholder.typicode.com/todos/1', {
completed: true,
}).then(response => response.json())
.then(todos => console.log(todos))
.catch(err => console.error(err));
// 4. DELETE 요청
request.delete('https://jsonplaceholder.typicode.com/todos/1')
.then(response => response.json())
.then(todos => console.log(todos))
.catch(err => console.error(err));