// GET 요청을 위한 비동기 함수
const get = url => {
const xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.send();
xhr.onload = () => {
if (xhr.status === 200) {
// 서버의 응답을 콘솔에 출력한다.
console.log(JSON.parse(xhr.response));
} else {
console.error(`${xhr.status} ${xhr.statusText}`);
}
};
};
// id가 1인 post를 취득
get('https://jsonplaceholder.typicode.com/posts/1');
/*
{
"userId": 1,
"id": 1,
"title": "sunt aut facere ...",
"body": "quia et suscipit ..."
}
*/
let g =0;
//비동기 함수인 setTimeout 함수는 콜백 함수의 처리 결과를 외부로 반환하거나 상위 스코프의 변수에 할당하지 못한다.
setTimeout(()=> {g = 100;}, 0}; // 100으로 바뀌질 않는다!
console.log(g); // 0
비동기 함수는,
1) 동기 처리 결과를 외부에 반환할 수 없고
2) 상위 스코프의 변수에 할당할 수도 없다
=> 따라서 비동기 함수의 처리결과에 대한 후속 처리는 함수 내부에서 수행해야 한다
=> 그러므로 비동기 함수를 범용적으로 사용하기 위해 비동기 함수에 비동기 처리 결과에 대한 후속 처리를 수행하는 콜백 함수를 전달하는 것이 일반적
// GET 요청을 위한 비동기 함수
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);
}
};
};
// id가 1인 post를 취득
// 서버의 응답에 대한 후속 처리를 위한 콜백 함수를 비동기 함수인 get에 전달해야 한다.
get('https://jsonplaceholder.typicode.com/posts/1', console.log, console.error);
/*
{
"userId": 1,
"id": 1,
"title": "sunt aut facere ...",
"body": "quia et suscipit ..."
}
*/
// GET 요청을 위한 비동기 함수
const get = (url, callback) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.send();
xhr.onload = () => {
if (xhr.status === 200) {
// 서버의 응답을 콜백 함수에 전달하면서 호출하여 응답에 대한 후속 처리를 한다.
callback(JSON.parse(xhr.response));
} else {
console.error(`${xhr.status} ${xhr.statusText}`);
}
};
};
const url = 'https://jsonplaceholder.typicode.com';
// id가 1인 post의 userId를 취득
get(`${url}/posts/1`, ({ userId }) => {
console.log(userId); // 1
// post의 userId를 사용하여 user 정보를 취득
get(`${url}/users/${userId}`, userInfo => {
console.log(userInfo); // {id: 1, name: "Leanne Graham", username: "Bret",...}
});
});
get('/step1', a => {
get(`/step2/${a}`, b => {
get(`/step3/${b}`, c => {
get(`/step4/${c}`, d => {
console.log(d);
});
});
});
});
try{
setTimeout(()=> { throw new Error('Error:'); }, 1000);
} catch (e) {
//에러를 캐치하지 못한다.
console.error('캐치한 에러', e);
}
// this를 보면 window
try{
setTimeout(()=> { console.log(this);}, 1000);
// Window {window: Window, self: Window, document: HTMLDocument, name: "", location: Location, …}
} catch (e) {
console.error('캐치한 에러', e);
}
// window.e를 호출해보면, 내가 만든 Error가 들어가 있다
try{
setTimeout(()=> { throw new Error('Error: 콘솔에 뜬다'); }, 1000);
} catch (e) {
console.log('여긴 안온다', e);
}
setTimeout(()=> {console.log(window.e);}, 2000);
/**
Error: Error: 콘솔에 뜬다
Error {}
message: "Error: 콘솔에 뜬다"
stack: "Error: Error: 콘솔에 뜬다↵ at https://9e1944c0-eddf-4830-9978-4b498e46f3f4.id.repl.co/javascript/index.js:2:27"
__proto__: Object
*/
// 프로미스 생성
const promise = new Promise((resolve, reject) => {
// Promise 함수의 콜백 함수 내부에서 비동기 처리를 수행한다.
if (/* 비동기 처리 성공 */) {
resolve('result');
} else { /* 비동기 처리 실패 */
reject('failure reason');
}
});
// GET 요청을 위한 비동기 함수
const promiseGet = url => {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.send();
xhr.onload = () => {
if (xhr.status === 200) {
// 성공적으로 응답을 전달받으면 resolve 함수를 호출한다.
resolve(JSON.parse(xhr.response));
} else {
// 에러 처리를 위해 reject 함수를 호출한다.
reject(new Error(xhr.status));
}
};
});
};
// promiseGet 함수는 프로미스를 반환한다.
promiseGet('https://jsonplaceholder.typicode.com/posts/1');
| 프로미스의 상태 정보 | 의미 | 상태 변경 조건 |
|---|---|---|
| pending | 비동기 처리가 아직 수행되지 않은 상태 | 프로미스가 생성된 직후 기본 상태 |
| fulfilled | 비동기 처리가 수행된 상태(성공) | resolve 함수 호출 |
| rejected | 비동기 처리가 수행된 상태(실패) | reject 함수 호출 |
프로미스의 상태는 resolve 또는 reject 함수를 호출하는 것으로 결정된다!
// 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
// rejected
new Promise((_, reject) => reject(new Error('rejected')))
.catch(e => console.log(e)); // Error: rejected
// catch는 사실 내부적으로 then을 사용하고 있다
new Promise((_, reject) => reject(new Error('rejected')))
.then(undefined, e => console.log(e)); // Error: rejected
new Promise(() => {})
.finally(() => console.log('finally')); // finally
const promiseGet = url => {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.send();
xhr.onload = () => {
if (xhr.status === 200) {
// 성공적으로 응답을 전달받으면 resolve 함수를 호출한다.
resolve(JSON.parse(xhr.response));
} else {
// 에러 처리를 위해 reject 함수를 호출한다.
reject(new Error(xhr.status));
}
};
});
};
// promiseGet 함수는 프로미스를 반환한다.
promiseGet('https://jsonplaceholder.typicode.com/posts/1')
.then(res => console.log(res))
.catch(err => console.error(err))
.finally(() => console.log('Bye!'));
const wrongUrl = 'https://jsonplaceholder.typicode.com/XXX/1';
//부적절한 URL이 지정되었기 때문에 에러가 발생한다.
promiseGet(wrongUrl).then(
res => console.log(res),
err => console.error(err)
); // Error:404
const wrongUrl = 'https://jsonplaceholder.typicode.com/XXX/1';
//부적절한 URL이 지정되었기 때문에 에러가 발생한다.
promiseGet(wrongUrl)
.then(res => console.log(res))
.catch(err => console.error(err)); // Error:404
const url = 'https://jsonplaceholder.typicode.com';
// id가 1인 post의 userId를 취득
promiseGet(`${url}/posts/1`)
// 취득한 post의 userId로 user 정보를 취득
.then(({ userId }) => promiseGet(`${url}/users/${userId}`))
.then(userInfo => console.log(userInfo))
.catch(err => console.error(err));
| 후속 처리 메서드 | 콜백 함수의 인수 | 후속 처리 메서드의 반환값 |
|---|---|---|
| then | promiseGet 함수가 반환한 프로미스가 resolve한 값 (예시에서 id가 1인 post) | 콜백 함수가 반환한 프로미스 |
| then | 첫 번째 then메서드가 반환한 프로미스가 resolve한 값 (예시에서 post의 userId로 취득한 user 정보) | 콜백 함수가 반환한 값(undefined)을 resolve한 프로미스 |
| catch (에러가 발생하지 않으면 호출되지 않음) | promiseGet 함수 또는 앞선 후속 처리 메서드가 반환한 프로미스가 reject한 값 | 콜백 함수가 반환한 값(undefined)을 resolve한 프로미스 |
// 배열을 resolve하는 프로미스를 생성
const resolvedPromise = Promise.resolve([1, 2, 3]);
resolvedPromise.then(console.log); // [1, 2, 3]
// 위 예제는 아래와 동일하게 동작
const resolvedPromise = new Promise(resolve => resolve([1, 2, 3]));
resolvedPromise.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));
// 세 개의 비동기 처리를 순차적으로 처리
const res = [];
requestData1()
.then(data => {
res.push(data);
return requestData2();
})
.then(data => {
res.push(data);
return requestData3();
})
.then(data => {
res.push(data);
console.log(res); // [1, 2, 3] ⇒ 약 6초 소요
})
.catch(console.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));
Promise.all([requestData1(), requestData2(), requestData3()])
.then(console.log) // [ 1, 2, 3 ] ⇒ 약 3초 소요
.catch(console.error);
Promise.all([
new Promise((_, reject) => setTimeout(() => reject(new Error('Error 1')), 3000)),
new Promise((_, reject) => setTimeout(() => reject(new Error('Error 2')), 2000)),
new Promise((_, reject) => setTimeout(() => reject(new Error('Error 3')), 1000))
])
.then(console.log)
.catch(console.log); // Error: Error 3
Promise.all([
1, // Promise.resolve(1)
2, // Promise.resolve(2)
3 // Promise.resolve(3)
])
.then(console.log) // [1,2,3]
.catch(console.log);
// GET 요청을 위한 비동기 함수
const promiseGet = url => {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.send();
xhr.onload = () => {
if (xhr.status === 200) {
// 성공적으로 응답을 전달받으면 resolve 함수를 호출한다.
resolve(JSON.parse(xhr.response));
} else {
// 에러 처리를 위해 reject 함수를 호출한다.
reject(new Error(xhr.status));
}
};
});
};
const githubIds = ['jeresig', 'ahejlsberg', 'ungmo2'];
Promise.all(githubIds.map(id => promiseGet(`https://api.github.com/users/${id}`)))
// [Promise, Promise, Promise] => Promise [userInfo, userInfo, userInfo]
.then(users => users.map(user => user.name))
// [userInfo, userInfo, userInfo] => Promise ['John Resig', 'Anders Hejlsberg', 'Ungmo Lee']
.then(console.log)
.catch(console.error);
Promise.race([
new Promise(resolve => setTimeout(() => resolve(1), 3000)), // 1
new Promise(resolve => setTimeout(() => resolve(2), 2000)), // 2
new Promise(resolve => setTimeout(() => resolve(3), 1000)) // 3
])
.then(console.log) // 3
.catch(console.log);
Promise.allSettled([
new Promise(resolve => setTimeout(() => resolve(1), 2000)),
new Promise((_, reject) => setTimeout(() => reject(new Error('Error!')), 1000))
]).then(console.log);
/*
[
{status: "fulfilled", value: 1},
{status: "rejected", reason: Error: Error! at <anonymous>:3:54}
]
*/
setTimeout(() => console.log(1), 0);
Promise.resolve()
.then(() => console.log(2))
.then(() => console.log(3));
const promise = fetch(url [, options])
fetch('https://jsonplaceholder.typicode.com/todos/1')
.then(response => console.log(response));
const wrongUrl = 'https://jsonplaceholder.typicode.com/XXX/1';
// 부적절한 URL이 지정되었기 때문에 404 Not Found 에러가 발생한다.
fetch(wrongUrl)
.then(() => console.log('ok'))
.catch(() => console.log('error'));
const wrongUrl = 'https://jsonplaceholder.typicode.com/XXX/1';
// 부적절한 URL이 지정되었기 때문에 404 Not Found 에러가 발생한다.
fetch(wrongUrl)
.then(response => {
if(!response.ok) throw new Error(response.statusText);
return response.json();
})
.then(todo => console.log(todo))
.catch(err => console.error(err));
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' });
}
};
request.get('https://jsonplacehoder.typicode.com/todos/1')
.then(response => {
if(!response.ok) throw new Error(response.statusText);
return response.json();
})
.then(todos => console.log(todos))
.catch(err => console.error(err));
// {userId: 1, id: 1, title: "deletus aut autem", completed: false}
request.post('https://jsonplaceholder.typicode.com/todos', {
userId: 1,
title: 'JavaScirpt',
completed: false
}).then(response => {
if(!response.ok) throw new Error(response.statusText);
return response.json();
})
.then(todos => console.log(todos))
.catch(err => console.error(err));
// {userId: 1, title: "JavaScript", completed: false, id: 201}
request.patch('https://jsonplaceholder.typicode.com/todos/1', {
completed: true
}).then(response => {
if(!response.ok) throw new Error(response.statusText);
return response.json();
})
.then(todos => console.log(todos))
.catch(err => console.lerror(err));
// {userId: 1, id: 1, title: "delectus aut autem", completed: true}
request.delete('https://jsonplaceholder.typicode.com/todos/1')
.then(response => {
if(!response.ok) throw new Error(response.statusText);
return response.json();
})
.then(todos => console.log(todos))
.catch(err => console.error(err));
// {}