๋๊ธฐ ์ฝ๋์ ์
console.log('This is synchronous...'); for(let i = 0; i < 1000000000; ++i){ console.log('I am blocking the main thread...'); } console.log('This is synchronous... Done!');
๋น๋๊ธฐ ์ฝ๋์ ์
setTimeout(()=> console.log('This is asynchronous...'), 5000); console.log('This is synchronous...'); for (let i = 0; i<1000000000; ++i) { console.log('I am blocking the main thread...'); }
setTimeout ํจ์๋ ๋น๋๊ธฐ ์ฝ๋, for๋ฌธ ์์ ์ ํ๋ ๋ฉ์ธ thread๊ฐ ์์ ์ ์ข ๋ฃํ์ง ์์๊ธฐ ๋๋ฌธ์, ์ค์ ํ ์๊ฐ๋ณด๋ค ๋ ๊ฑธ๋ฆฐ๋ค.
reliableํ์ง ์์ setTimeout ์ฝ๋.
๋ธ๋ผ์ฐ์ ์ main thread๋ ์๋ฐ์คํฌ๋ฆฝํธ ์ฝ๋์์ ๋๊ธฐ์ ์ผ๋ก ์ฒ๋ฆฌ๋์ด์ผ ํ ์ฝ๋ ์คํ ์ธ, ์น ํ์ด์ง๋ฅผ ์ค์๊ฐ์ผ๋ก ๋ ๋๋งํ๊ณ , ์ ์ ์ ์ ๋ ฅ์ ๊ฐ์งํ๊ณ ๋คํธ์ํฌ ํต์ ์ ์ฒ๋ฆฌํ๋ ๋ฑ ์๋ง์ ์ผ์ ์ฒ๋ฆฌํด์ผํ๋.
๋น๋๊ธฐ ์์ ์ ํ ๋นํ๋ฉด, ๋น๋๊ธฐ ์ฒ๋ฆฌ๊ฐ ๋๋๊ณ ๋ธ๋ผ์ฐ์ ๋ task queue์ ์คํ ์ฝ๋๋ฅผ ๋ฃ๋๋ค.
main thread๋ event loop๋ฅผ ๋๋ ค task queue์ ์์ ์ด ์๋ ์ง ์ฒดํฌ
์์ ์ด ์์ผ๋ฉด task๋ฅผ ์คํํ๋ค.
๋ค๋ฅธ ๋น๋๊ธฐ์ ์
// task queue์ callback ํจ์๊ฐ ๋๊ฒจ์ง๋ ๊ฒ์ ๋น๋๊ธฐ ์ฒ๋ฆฌ request('user-data', (userData)=> { console.log('userData ๋ก๋'); saveUsers(userData); }); // ๋ ๋ณ๊ฒฝ ๋๊ธฐ ์ฒ๋ฆฌ console.log('DOM ๋ณ๊ฒฝ'); console.log('์ ์ ์ ๋ ฅ');
requestํจ์๋ฅผ ํธ์ถํด์ ๋น๋๊ธฐ ์ฒ๋ฆฌ๋ฅผ ๋ฑ๋กํ๊ณ , console.log๋ฅผ ์คํ
Callback pattern - Single request : fetchUserAddresss
function fetchUsers(onSuccess){ request('/users', onSuccess); // ํ๋์ request์ ๊ฒฝ์ฐ, onSuccess์ ํด๋นํ๋ callback์ ๋๊น // ๊ฐ๋จํ๋ค. }
Promise - Single request : fetchUserAddress
function fetchUsers(onSuccess){ return request('/users').then(onSuccess); // requestํจ์๊ฐ Promise๋ฅผ ๋ฐํ. Promise.then();์ผ๋ก ๋ฐ์ // onSuccess callback์ ๋๊ธด๋ค. // ํน์ return request('/users'); }
Promise - Error handling
function fetchUsers(onSuccess, onError){ return request('/users') .then(onSuccess) .then(onError); //ํน์ return request('/users').then(onSuccess, onError); }
Callback pattern - Multiple request
function fetchUserAddress(onSuccess){ request('/users', (userData) => { const userDataWithAddress = []; const userLength = userData.length; userData.map(user=> request(`/users/${user.userId}/address`, (address)=>{ userDataWithAddress.push({...user, address}); if(userDataWithAddress.length === userLength) { onSuccess(userDataWithAddress); } }) }) } //์ ์ ์ ๊ฐ์๋งํผ ๋น๋๊ธฐ ์ฒ๋ฆฌ๋ฅผ ํ๋ค.
Promise - Multiple request
function fethchUserAddress(){ // request๋ก ๋น๋๊ธฐ ์์ฒญ์ ํ์ฌ ์ ์ ๋ชฉ๋ก์ ๋ฐ์์จ๋ค. // then๋ฉ์๋๋ก ๋ฐ์ดํฐ๋ฅผ ๋ฐ์ ์ฒ๋ฆฌ return request('/users').then((userData)=>{ //user ๋ฐ์ดํฐ๋ฅผ map๋ฉ์๋๋ก ์ ์ ์ address ์ ๋ณด๋ฅผ ํฉ์ณ // ์๋ก์ด ๋ฐฐ์ด ์์ฑํจ. ๊ฒฐ๊ตญ user adress๋ฅผ ํฉ์น ๋ฐฐ์ด์ ๋ฐํ Promise.all( userData.map((user)=> request(`/users/{user.userId}/address`).then((addresss)=>({ ...user, address, }) ) ); }) }
Promise์ ์ ์: Promise ๊ฐ์ฒด๋, ๊ฐ์ฒด๊ฐ ์์ฑ ๋น์์๋ ์๋ ค์ง์ง ์์ ๋ฐ์ดํฐ์ ๋ํ Proxy์ด๋ค.
[request('/user') ์์๋ '/user'๊ฐ ์ด๋ค ๋ฐ์ดํฐ์ธ์ง ์๋ ค์ ธ ์์ง ์๋ ์ํ.
.then(userData=>{...})๋ก ๋ช
์ ํ ์ด๋ ํ ์์
์ ํ๋ค.]
Promise ์์
function returnPromise() { // Promise ๊ฐ์ฒด๋ฅผ ๋ฐํํ๋๋ฐ, ์์ฑ์๋ resolve, reject ํจ์ ์ธ์๋ฅผ ๊ฐ์ง๋ค. return new Promise((resolve, reject)=>{ setTimeout(()=>{ // Promise ์ธ์ callback ํจ์๋ฅผ ๊ฐ์ง๊ณ ๋น๋๊ธฐ ์ฒ๋ฆฌ const randomNumber = generateRandomNumber(100); if (randomNumber < 50) resolve(randomNumber); else reject(new Error('Random number is too small.')); }, 1000); }); }
retrunPromise()
// ์ ์์ ์ธ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์ ์ฒ๋ฆฌ
.then(num => {
console.log('First random number : ',num);
})
//์๋ฌ๋ฅผ ๋ฐ์ ์ฒ๋ฆฌ
.catch(error=>{
console.error('Error occured: ', error);
})
// ์์ ์ฝ๋๊ฐ ์ฒ๋ฆฌ๊ฐ ๋์์ ๋ ๋ง์ง๋ง์ผ๋ก ํธ์ถํ๊ธฐ ๋๋ฌธ์,
// ์ธ์๋ฅผ ๋ฐ์ ์ ์๊ณ , ํด๋ฆฐ ์
ํ๊ฒ ๋์ํ๋ค.
.finally(()=>{
console.log('Promise returned');
});
Promise ๊ฐ์ฒด๋ pending, fulfilled, rejected์ 3๊ฐ์ ์ํ๋ฅผ ๊ฐ์ง๋ค.
fulfilled, rejected ๋ ์ํ๋ฅผ settled๋ผ๊ณ ์ง์นญํ๋ค.
pending์ ๋น๋๊ธฐ ์คํ์ด ๋๋๊ธฐ๋ฅผ ๊ธฐ๋ค๋ฆฌ๋ ์ํ๋ฅผ ์ง์นญ.
fulfilled๋ ๋น๋๊ธฐ ์คํ์ด ์ฑ๊ณตํ ์ํ.
rejected๋ ๋น๋๊ธฐ ์คํ์ด ์คํจํ ์ํ.
then, catch๋ ๋น๋๊ธฐ(Promise), ๋๊ธฐ(sync) ์คํ ์ค ์ด๋ค ๊ฒ์ด๋ผ๋ ๋ฆฌํดํ ์ ์๋ค.
Promise.all
Promise.all( // ๊ฐ user์ user.name์ ๊ธฐ๋ฐ์ผ๋ก detail ์ ๋ณด๋ฅผ ์ป์ด์จ๋ค. // [Promise, Promise, Promise] users.map(user => request('/users/detail', user.name)) // ๊ฐ Promise๊ฐ resolveํ ๋ฐ์ดํฐ๋ค์ ํ๋๋ก ๋ชจ์ ๋ฐฐ์ด .then(console.log) .catch(e => console.error('ํ๋๋ผ๋ ์คํจํ์ต๋๋ค.')); );
Promise.allSettled
function saveLogRetry(logs, retryNum){ if(retryNum >= 3) return; // no more retry Promise.allSettled(logs.map(saveLog)) .then((result)=>{ return results.filter((result)=>result.status === 'rejected'); }) .then((failedPromises)=>{ saveLogRetry( failedPromises.map((promise) => promise.reason.filedLog), retryNum + 1 ); }) }
Promise.race
function requestWithTimeout(request, timeout = 1000) { return Promise.race([request, wait(timeout)]).then((data)=>{ console.log('์์ฒญ ์ฑ๊ณต.'); return data; }); } requestWithTimeout(req) .then(data => console.log('data : ', data)) .catch(()=> console.log('ํ์์์ ์๋ฌ!'));
Promise.any: ์ด๋ค Promise์ ๋ฐฐ์ด์ ๋ฐ์ ์ด๋ค ๊ฒ์ด๋ผ๋ ๊ฐ์ฅ ๋จผ์ fulfilled๋ Promise์ ๊ฒฐ๊ณผ๋ฅผ then()์ผ๋ก ๋๊ธด๋ค.
function getAnyData(dataList) { Promise.any(dataList.map((data) => request(data.url))) .then((data) => { console.log('๊ฐ์ฅ ์ฒซ ๋ฒ์งธ๋ก ๊ฐ์ ธ์จ ๋ฐ์ดํฐ : ', data); }) .catch((e) => { console.log('์๋ฌด๊ฒ๋ ๊ฐ์ ธ์ค์ง ๋ชปํ์ต๋๋ค.'); }); }
Promise.any
Promise.resolve() .then(()=> wait2(5000).then(()=> console.log('500 waited.'))) .then(()=> console.log('After 500 wait.') return wait2(1000).then(()=> console.log('100 waited.')) }) .then(()=> console.log('DONE')); /* 500 waited. After 500 wait. 1000 waited. DONE. */
async/await: Promise๋ก ์์ฑํ๋ ๊ฒ ๋ณด๋ค ์ง๊ด์
async function fetchUser(){ try{ const users = await request('/user'); console.log('users fetched.'); return users } catch (e) { console.log('error : ', e); } }
Promise
function fetchUsers() { return request('/users') .then(users=>console.log('users fetched.')) .catch(e=> console.error('error: ' e)); }
async function fetchUserWithAddress(id){
try{
const user = await request(`/user/${id}`);
const address = await request(`/user/${user.id}/address`);
} catch (e) {
console.log('error : ', e);
}
}
async function fetchUserWithAddress(id){
let user = null;
try {
user = await request(`/user/${user.id}`)
} catch(e) {
console.log('user fetch error: ', e);
return
}
try {
const address = await request(`/user/${user.id}/address`)
return {...user, address}
} catch (e){
console.log('Address fetch error: ', e);
}
}
async function fetchUserWithAddress(id) {
try {
const user = await request(`/user/${user.id}`)
if(!user) throw new Error('No user found');
const address = await request(`/user/${user.id}/address`);
if(!address.userId !== user.id) throw new Error('No address match with user.');
return {...user, address}
} catch (e) {
console.log('User fetch error: ', e);
}
}
}
try ๊ตฌ๋ฌธ ์์์ user์ address๋ฅผ ์์ฐจ์ ์ผ๋ก ๊ฐ์ ธ์, ํ๊บผ๋ฒ์ ๋ฐํ
try...catch ๋ฌธ ์์ ๋ try...catch ๋ฌธ์ ๋ฃ์ด nesting ๋ ๊ตฌ์กฐ๋ฅผ ๊ฐ์ง๊ณ ์๋ค.
async function fetchUserWithAddress(id){
try {
const user = await request(`/user/${user.id}`);
const address = await request(`/user/${user.id}/address`);
return {...user, address}
} catch (e) {
try {
sendErrorLog(e)
} catch (e) {
console.error('์๋ฌ๋ฅผ ๋ก๊น
ํ๋๋ฐ ์คํจํ์์ต๋๋ค.');
}
}
}
async function fetchUserWithAddress(id){
return await Promise.all([
// user์ address๋ฅผ ๋์์ ํธ์ถํ ์ํฉ
(async () => await request(`/users/${user.id}`))(),
(async () => await request(`/users/${user.id}/address`))(),
]);
}
fetchUserWithAddress('1234')
//user์ address๋ฅผ ๋์์ ๋ฐ๋ ์ฒ๋ฆฌ๋ฅผ ํ ์ ์๋ค.
.then(([user, address]) => ({...user, address}))
.catch(e => console.log('Error: ', e));
์๋๋ ์๋ฒ์ ํต์ ํ๊ธฐ ์ํ ์ฌ๋ฌ๊ฐ์ง ๋๊ตฌ๋ค์ด๋ค.
Auth, header, payload, query๋ฑ API ์์ฒญ์ ํ์ํ ๋ฐ์ดํฐ๋ฅผ ์ฝ๊ฒ ์ธํ
ํ ์ ์๋ค.
๋ค๋ฅธ ๊ฐ๋ฐ์๊ฐ ์ฝ๊ฒ ์
์
ํด ํ
์คํธํ ์ ์๋๋ก API ์ ๋ณด๋ฅผ ๊ณต์ ํ ์ ์๋ค.
Request๋ฅผ ๋ชจ์ Collection์ผ๋ก ๋ง๋ค์ด, API๋ฅผ ์ข
๋ฅ๋ณ๋ก ๊ด๋ฆฌํ๋ค.
ํ๊ฒฝ ๋ณ์๋ฅผ ์ ์ํ์ฌ, ํ๊ฒฝ๋ณ๋ก ํ
์คํธ๊ฐ ๊ฐ๋ฅํ๋ค.
API์ method, endpoint๋ฅผ ์ ์ํ๋ค.
endpoint๋ง๋ค ์ธ์ฆ ๋ฐฉ์, content type ๋ฑ์ ์ ์ํ๋ค.
body data, query string, path variable๋ฑ์ ์ ์ํ๋ค.
์์ฒญ, ์๋ต ๋ฐ์ดํฐ ํ์๊ณผ ํ์
์ ์ ์, data model์ ํ์ฉํ๋ค(schema).
๊ทธ๋ฌ๋, ๋ณดํต ์๋ฒ์ endpoint์ ํํ์ด์ง domain์ ๋ค๋ฅธ ๊ฒฝ์ฐ๊ฐ ๋ง๋ค.๋ฐ๋ผ์ ์๋ฒ์์๋ ํํ์ด์ง domain์ ํ์ฉํด์ ๋ค๋ฅธ domain์ด๋ผ ํ๋๋ผ๋ ์์ฒญ์ ๋ณด๋ผ ์ ์๊ฒ ํ๋ค.
์๋ฒ๋ Access-Control-Allow-Origin ์ธ์ Accsess-Control-์ ํฌํจํ๋ ํค๋์ CORS ๊ด๋ จ ์ ๋ณด๋ฅผ ํด๋ผ์ด์ธํธ๋ก ๋ณด๋ธ๋ค.
same-origin policy
์น์ฌ์ดํธ์ ์
์ฑ script๊ฐ ๋ก๋๋์ด, ์์ํ ์์ฒญ์ ํ๋ ๊ฒ์ ๋ง๊ธฐ ์ํจ์ด๋ค.
๋ฐ๋๋ก, ์ต๋ช
์ ์ ๋ก๋ถํฐ์ DDos๊ณต๊ฒฉ ๋ฑ์ ๋ง๊ธฐ ์ํจ.
์๋ฒ์ ์ง์ CORS ์ค์ ์ ํ ์ ์๋ค๋ฉด, Proxy ์๋ฒ ๋ฑ์ ๋ง๋ค์ด ํด๊ฒฐํ๋ค.
ํ ์คํ: ์ด๊ฑฐ์ ๋ญ์๋ค๋ฅ.. ์ผ๋จ์ ๋ฏธ๋์ ๋๋ฅผ ์ํ์ฌ ์ ๋ฆฌํด๋ณธ๋ค.