15_Oct_2021 ๐Ÿฐ์—˜๋ฆฌ์Šค AI ํŠธ๋ž™ TIL: ๋น„๋™๊ธฐ ํ†ต์‹  & Promise

์œ ํ™˜์ตยท2021๋…„ 10์›” 16์ผ
0

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ๋น„๋™๊ธฐ

  • ์ดˆ๊ธฐ ์›น ํ™˜๊ฒฝ: ์„œ๋ฒ„์—์„œ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ๋กœ๋“œํ•˜์—ฌ ํŽ˜์ด์ง€ ๋นŒ๋“œํ•จ, ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ๋Š” ๋ณ„๋„์˜ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์•˜๋‹ค.
  • AJAX(Asynchronous JavaScript and XML) ๊ธฐ์ˆ ์˜ ๋“ฑ์žฅ์œผ๋กœ ํŽ˜์ด์ง€ ๋กœ๋“œ ์—†์ด client-side์—์„œ ์„œ๋ฒ„๋กœ ์š”์ฒญ์„ ๋ณด๋‚ด ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค.
  • XMLHttpRequest๋ผ๋Š” ๊ฐ์ฒด๋ฅผ ์ด์šฉํ•ด ์„œ๋ฒ„๋กœ ์š”์ฒญ์„ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ๋น„๋™๊ธฐ

  • ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” single-threaded language์ด๋ฏ€๋กœ, ๋งŒ์ผ ์„œ๋ฒ„ ์š”์ฒญ์„ ๊ธฐ๋‹ค๋ ค์•ผ ํ•œ๋‹ค๋ฉด ์œ ์ €๋Š” ๋ฉˆ์ถฐ์žˆ๋Š” ๋ธŒ๋ผ์šฐ์ €๋ฅผ ๋ณด๊ฒŒ ๋œ๋‹ค.
  • ๋”ฐ๋ผ์„œ ๋™๊ธฐ๊ฐ€ ์•„๋‹Œ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ์ด์šฉํ•ด ์„œ๋ฒ„๋กœ ํ†ต์‹ ํ•  ํ•„์š”๊ฐ€ ์žˆ๋‹ค.
  • ๋น„๋™๊ธฐ ์š”์ฒญ ํ›„, main thread๋Š” ์œ ์ €์˜ ์ž…๋ ฅ์„ ๋ฐ›๊ฑฐ๋‚˜, ํŽ˜์ด์ง€๋ฅผ ๊ทธ๋ฆฌ๋Š” ๋“ฑ์˜ ์ž‘์—…์„ ์ฒ˜๋ฆฌ.
  • ๋น„๋™๊ธฐ ์‘๋‹ต์„ ๋ฐ›์œผ๋ฉด, ์‘๋‹ต์„ ์ฒ˜๋ฆฌํ•˜๋Š” callback ํ•จ์ˆ˜๋ฅผ task queue์— ๋„ฃ๋Š”๋‹ค.
  • event loop๋Š” main thread์— ์—ฌ์œ ๊ฐ€ ์žˆ์„ ๋•Œ task queue์—์„œ ํ•จ์ˆ˜๋ฅผ ๊บผ๋‚ด ์‹คํ–‰ํ•œ๋‹ค.

๋™๊ธฐ vs ๋น„๋™๊ธฐ

  • ๋™๊ธฐ(synchronous)์ฝ”๋“œ๋Š”, ํ•ด๋‹น ์ฝ”๋“œ ๋ธ”๋ก์„ ์‹คํ–‰ํ•  ๋•Œ์— thread์˜ ์ œ์–ด๊ถŒ์„ ๋„˜๊ธฐ์ง€ ์•Š๊ณ  ์ˆœ์„œ๋Œ€๋กœ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.

๋™๊ธฐ ์ฝ”๋“œ์˜ ์˜ˆ

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!');

๋น„๋™๊ธฐ(asynchronous)์ฝ”๋“œ๋Š”, ์ฝ”๋“œ์˜ ์ˆœ์„œ์™€ ๋‹ค๋ฅด๊ฒŒ ์‹คํ–‰๋œ๋‹ค.

  • ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ์ฝ”๋“œ๋ฅผ ๊ฐ์‹ผ ๋ธ”๋ก์€ task queue์— ๋„ฃ์–ด์ง„๋‹ค.
  • main thread๊ฐ€ ๋™๊ธฐ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•œ ํ›„, ์ œ์–ด๊ถŒ์ด ๋Œ์•„์™”์„ ๋•Œ event loop๊ฐ€ task queue์— ๋„ฃ์–ด์ง„ ๋น„๋™๊ธฐ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.

๋น„๋™๊ธฐ ์ฝ”๋“œ์˜ ์˜ˆ

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 ์ฝ”๋“œ.

๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ ๋‚ด๋ถ€ ๊ตฌ์กฐ

  • ๋ธŒ๋ผ์šฐ์ €์—์„œ ์‹คํ–‰๋˜๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๋Š” event driven ์‹œ์Šคํ…œ์œผ๋กœ ์ž‘๋™ํ•œ๋‹ค. (๋ชจ๋“ˆ์— ์š”์ฒญ์ด ์˜ค๋ฉด task queue์— callback ํ•จ์ˆ˜๋ฅผ ๋„ฃ๋Š”๋‹ค ๊ทธ๋ฆฌ๊ณ  ์ด๋ฒคํŠธ ๋ฐœ์ƒ ์‹œ task queue์—์„œ ์‹คํ–‰ํ•œ๋‹ค.)
  • ์›น์•ฑ์„ ๋กœ๋“œํ•˜๋ฉด ๋ธŒ๋ผ์šฐ์ €๋Š” HTML document๋ฅผ ์ฝ์–ด ๋ฌธ์„œ์— ์žˆ๋Š” CSS code, JS code๋ฅผ ๋ถˆ๋Ÿฌ์˜จ๋‹ค.
  • ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์—”์ง„์€ ์ฝ”๋“œ๋ฅผ ์ฝ์–ด ์‹คํ–‰๋œ๋‹ค.

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๊ฐ€ ๋™์ž‘ํ•˜๋Š” ๋‚ด๋ถ€ ๊ตฌ์กฐ

  • ๋ธŒ๋ผ์šฐ์ €์˜ 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๋ฅผ ์‹คํ–‰

Promise

Callback Pattern vs Promise

Callback Pattern

  • ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ํ›„ ์‹คํ–‰ ๋  ์ฝ”๋“œ๋ฅผ Callback function์œผ๋กœ ๋ณด๋‚ด๋Š” ๊ฒƒ์ด๋‹ค. (e.g. setTimeout). callback ํ•จ์ˆ˜ ๋งŒ์œผ๋กœ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ๋‹ค๋ฅธ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ์ด์–ด์„œ ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.
  • ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๊ฐ€ ๊ณ ๋„ํ™”๋˜๋ฉฐ, Callback hell๋“ฑ์˜ ๋‹จ์ ์ด ๋ถ€๊ฐ๋˜์—ˆ๋‹ค.
    (Callback hell: callback ํ•จ์ˆ˜ ๋‚ด์— ๋˜ ๋‹ค๋ฅธ callback ํ•จ์ˆ˜๊ฐ€ ์กด์žฌํ•˜์—ฌ, ๊ณ„์†ํ•ด์„œ ๋„ค์ŠคํŒ…๋˜๋Š” ๊ฒƒ)

Promise

  • Promise๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ์˜ ์ˆœ์„œ ์กฐ์ž‘, ์—๋Ÿฌ ํ•ธ๋“ค๋ง, ์—ฌ๋Ÿฌ ๋น„๋™๊ธฐ ์š”์ฒญ ์ฒ˜๋ฆฌ ๋“ฑ์„ ์‰ฝ๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.
    (Nesting ๋œ ๊ฒƒ์„ ํ’€์–ด์„œ ํ•˜๋‚˜์˜ ๊นŠ์ด๋กœ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๋Š” ๊ฐ์ฒด)

Callback pattern vs Promise ์˜ˆ์‹œ ๋น„๊ต

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์˜ ์ •์˜: Promise ๊ฐ์ฒด๋Š”, ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ ๋‹น์‹œ์—๋Š” ์•Œ๋ ค์ง€์ง€ ์•Š์€ ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•œ Proxy์ด๋‹ค.
[request('/user') ์‹œ์—๋Š” '/user'๊ฐ€ ์–ด๋–ค ๋ฐ์ดํ„ฐ์ธ์ง€ ์•Œ๋ ค์ ธ ์žˆ์ง€ ์•Š๋Š” ์ƒํƒœ.
.then(userData=>{...})๋กœ ๋ช…์‹œ ํ›„ ์–ด๋– ํ•œ ์ž‘์—…์„ ํ•œ๋‹ค.]

  • ๋น„๋™๊ธฐ ์‹คํ•ด์ด ์™„๋ฃŒ๋œ ํ›„์—, '.then()', '.catch()', '.finally()' ๋“ฑ์˜ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ๋ถ™์—ฌ ๊ฐ๊ฐ์˜ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ๋กœ์ง, ์—๋Ÿฌ ์ฒ˜๋ฆฌ ๋กœ์ง, ํด๋ฆฐ์—… ๋กœ์ง์„ ์‹คํ–‰ํ•œ๋‹ค.
  • then() ์ฒด์ธ์„ ๋ถ™์—ฌ, ๋น„๋™๊ธฐ ์‹คํ–‰์„ ๋งˆ์น˜ ๋™๊ธฐ ์‹คํ–‰์ฒ˜๋Ÿผ ๋™์ž‘ํ•˜๋„๋ก ํ•œ๋‹ค.

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 ๊ฐ์ฒด์˜ ์ƒํƒœ

Promise ๊ฐ์ฒด๋Š” pending, fulfilled, rejected์˜ 3๊ฐœ์˜ ์ƒํƒœ๋ฅผ ๊ฐ€์ง„๋‹ค.

  • fulfilled, rejected ๋‘ ์ƒํƒœ๋ฅผ settled๋ผ๊ณ  ์ง€์นญํ•œ๋‹ค.

  • pending์€ ๋น„๋™๊ธฐ ์‹คํ–‰์ด ๋๋‚˜๊ธฐ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋Š” ์ƒํƒœ๋ฅผ ์ง€์นญ.

  • fulfilled๋Š” ๋น„๋™๊ธฐ ์‹คํ–‰์ด ์„ฑ๊ณตํ•œ ์ƒํƒœ.

  • rejected๋Š” ๋น„๋™๊ธฐ ์‹คํ–‰์ด ์‹คํŒจํ•œ ์ƒํƒœ.

  • then, catch๋Š” ๋น„๋™๊ธฐ(Promise), ๋™๊ธฐ(sync) ์‹คํ–‰ ์ค‘ ์–ด๋–ค ๊ฒƒ์ด๋ผ๋„ ๋ฆฌํ„ดํ•  ์ˆ˜ ์žˆ๋‹ค.

Multiple Promise handling

  • Promise.all()์€ ๋ชจ๋“  Promise๊ฐ€ fulfilled ๋˜๊ธธ ๊ธฐ๋‹ค๋ฆฐ๋‹ค.
    ํ•˜๋‚˜๋ผ๋„ ์—๋Ÿฌ ๋ฐœ์ƒ ์‹œ , ๋ชจ๋“  Promise ์š”์ฒญ์ด ์ค‘๋‹จ๋œ๋‹ค.
  • Promise.allSettled()๋Š” ๋ชจ๋“  Promise๊ฐ€ settled ๋˜๊ธธ ๊ธฐ๋‹ค๋ฆฐ๋‹ค.
  • Prmise.race()๋Š” ๋„˜๊ฒจ์ง„ Promise๋“ค ์ค‘ ํ•˜๋‚˜๋ผ๋„ settled ๋˜๊ธฐ๋ฅผ ๊ธฐ๋‹ค๋ฆฐ๋‹ค.
  • Promise.any() ๋„˜๊ฒจ์ง„ Promise ์ค‘ ํ•˜๋‚˜๋ผ๋„ fulfilled ๋˜๊ธธ ๊ธฐ๋‹ค๋ฆฐ๋‹ค.

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 chaining, nested promise

  • Promise ๊ฐ์ฒด๋Š”, settled ๋˜๋”๋ผ๋„ ๊ณ„์† ํ•ธ๋“ค๋Ÿฌ๋ฅผ ๋ถ™์ผ ์ˆ˜ ์žˆ๋‹ค.
  • ํ•ธ๋“ค๋Ÿฌ๋ฅผ ๋ถ™์ธ ์ˆœ์„œ๋Œ€๋กœ ํ˜ธ์ถœ๋œ๋‹ค.
  • catch ๋’ค์— ๊ณ„์† ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ๋ถ™์–ด์žˆ๋‹ค๋ฉด, ์—๋Ÿฌ๋ฅผ ์ฒ˜๋ฆฌํ•œ ํ›„์— ๊ณ„์† ์ง„ํ–‰๋œ๋‹ค. ์ด๋•Œ๋Š” catch์—์„œ ๋ฆฌํ„ดํ•œ ๊ฐ’์ด then์œผ๋กœ ์ „๋‹ฌ๋œ๋‹ค

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 ์ฒด์ธ์„ ๊ตฌ์ถ•ํ•˜์ง€ ์•Š๊ณ ๋„, Promise๋ฅผ ์ง๊ด€์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ฌธ๋ฒ•.
  • ๋งŽ์€ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด์— ์žˆ๋Š” try...catch ๋ฌธ์œผ๋กœ ์—๋Ÿฌ๋ฅผ ์ง๊ด€์ ์œผ๋กœ ์ฒ˜๋ฆฌ.
  • async function์„ ๋งŒ๋“ค๊ณ , Promise๋ฅผ ๊ธฐ๋‹ค๋ ค์•ผ ํ•˜๋Š” ํ‘œํ˜„ ์•ž์— await์„ ๋ถ™์ธ๋‹ค.

Async/await vs Promise ๋น„๊ต

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));
}

์—ฌ๋Ÿฌ ๊ฐœ์˜ await

  • ์—ฌ๋Ÿฌ ๊ฐœ์˜ await์„ ์ˆœ์„œ๋Œ€๋กœ ๋‚˜์—ดํ•˜์—ฌ, then chain์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • try ... catch ๋ฌธ์„ ์ž์œ ๋กญ๊ฒŒ ํ™œ์šฉํ•˜์—ฌ ์—๋Ÿฌ ์ฒ˜๋ฆฌ๋ฅผ ์ ์šฉํ•œ๋‹ค.
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);
    }
}
  • ์ค‘๊ฐ„์— ์ƒˆ๋กœ์šด ์—๋Ÿฌ๋ฅผ ๋˜์ง€๋Š” ๊ฒฝ์šฐ: ์ปค์Šคํ…€ ์—๋Ÿฌ๋ฅผ ์ง์ ‘ ๋˜์ ธ, ๋งˆ์ง€๋ง‰ catch ๋ฌธ์„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค. Promise๋กœ ์ฒ˜๋ฆฌํ•˜๊ธฐ ๊นŒ๋‹ค๋กœ์šด ๋ถ€๋ถ„ ํ•ด๊ฒฐ.
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/await - Promise์™€์˜ ์กฐํ•ฉ

  • Promise.all์€, ํŠน์ • ๋น„๋™๊ธฐ ์ž‘์—…์ด ์ƒ๋Œ€์ ์œผ๋กœ ๋น ๋ฅด๊ฒŒ ๋๋‚˜๋„, ๋Š๋ฆฐ ์ฒ˜๋ฆฌ๋ฅผ ๋๊นŒ์ง€ ๊ธฐ๋‹ค๋ ค์•ผ๋งŒ ํ•œ๋‹ค.
  • ์ด์™€ ๋‹ฌ๋ฆฌ, async/await์„ ํ™œ์šฉํ•  ๊ฒฝ์šฐ parallelism์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋Š” ๋๋‚œ ๋Œ€๋กœ ๋จผ์ € ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์ด๋‹ค.
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));

POSTMAN, Open API CORS

์•„๋ž˜๋Š” ์„œ๋ฒ„์™€ ํ†ต์‹ ํ•˜๊ธฐ ์œ„ํ•œ ์—ฌ๋Ÿฌ๊ฐ€์ง€ ๋„๊ตฌ๋“ค์ด๋‹ค.

POSTMAN

  • ์„œ๋ฒ„์™€์˜ ํ†ต์‹ ์„ ์œ„ํ•ด API๋ฅผ ํ™œ์šฉํ•˜๋Š” ๊ฒฝ์šฐ, React ์•ฑ์œผ๋กœ๋งŒ ์š”์ฒญํ•˜์—ฌ API๊ฐ€ ์ž˜ ๋™์ž‘ํ•˜๋Š”์ง€ ์•Œ์•„๋ณด๋Š” ๋ฐฉ๋ฒ•์€ ๋น„ํšจ์œจ์ ์ด๋‹ค.
  • ์ˆ˜๋งŽ์€ API์˜ endpoint์™€ ์‹คํ–‰ ์กฐ๊ฑด๋“ค์„ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์€ ํž˜๋“œ๋ฏ€๋กœ,
  • ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•œ ๊ฐœ๋ฐœ๋„๊ตฌ์ธ POSTMAN์„ ํ™œ์šฉํ•˜์—ฌ API๋ฅผ ํ…Œ์ŠคํŠธํ•œ๋‹ค.

์žฅ์ 

Auth, header, payload, query๋“ฑ API ์š”์ฒญ์— ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์‰ฝ๊ฒŒ ์„ธํŒ…ํ•  ์ˆ˜ ์žˆ๋‹ค.
๋‹ค๋ฅธ ๊ฐœ๋ฐœ์ž๊ฐ€ ์‰ฝ๊ฒŒ ์…‹์—…ํ•ด ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ๋„๋ก API ์ •๋ณด๋ฅผ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ๋‹ค.
Request๋ฅผ ๋ชจ์•„ Collection์œผ๋กœ ๋งŒ๋“ค์–ด, API๋ฅผ ์ข…๋ฅ˜๋ณ„๋กœ ๊ด€๋ฆฌํ•œ๋‹ค.
ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฅผ ์ •์˜ํ•˜์—ฌ, ํ™˜๊ฒฝ๋ณ„๋กœ ํ…Œ์ŠคํŠธ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.

Open API

  • RESTful API๋ฅผ ํ•˜๋‚˜์˜ ๋ฌธ์„œ๋กœ ์ •์˜ํ•˜๊ธฐ ์œ„ํ•œ ๋ฌธ์„œ ํ‘œ์ค€.
  • OpenAPI Specification(OAS)์œผ๋กœ ์ •์˜๋จ.
  • Swagger ๋“ฑ์˜ ํˆด๋กœ, OpenAPI๋กœ ์ž‘์„ฑ๋œ ๋ฌธ์„œ๋ฅผ Parsing ํ•ด ํ…Œ์ŠคํŒ… ๋„๊ตฌ๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.
  • ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์ž, ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ์ž์™€์˜ ํ˜‘์—… ์‹œ ์ฃผ์š”ํ•œ ๋„๊ตฌ๋กœ ์‚ฌ์šฉํ•œ๋‹ค.

API์˜ method, endpoint๋ฅผ ์ •์˜ํ•œ๋‹ค.
endpoint๋งˆ๋‹ค ์ธ์ฆ ๋ฐฉ์‹, content type ๋“ฑ์„ ์ •์˜ํ•œ๋‹ค.
body data, query string, path variable๋“ฑ์„ ์ •์˜ํ•œ๋‹ค.
์š”์ฒญ, ์‘๋‹ต ๋ฐ์ดํ„ฐ ํ˜•์‹๊ณผ ํƒ€์ž…์„ ์ •์˜, data model์„ ํ™œ์šฉํ•œ๋‹ค(schema).

CORS

  • Cross-Origin Resource Sharing
  • ๋ธŒ๋ผ์šฐ์ €๋Š” ๋ชจ๋“  ์š”์ฒญ ์‹œ Origin ํ—ค๋”๋ฅผ ํฌํ•จํ•œ๋‹ค.
  • ์„œ๋ฒ„๋Š” Origin ํ—ค๋”๋ฅผ ๋ณด๊ณ , ํ•ด๋‹น ์š”์ฒญ์ด ์›ํ•˜๋Š” ๋„๋ฉ”์ธ์—์„œ๋ถ€ํ„ฐ ์ถœ๋ฐœํ•œ ๊ฒƒ์ธ์ง€๋ฅผ ํŒ๋‹จํ•œ๋‹ค.
  • ๋‹ค๋ฅธ Origin์—์„œ ์˜จ ์š”์ฒญ์€ ์„œ๋ฒ„์—์„œ ๊ธฐ๋ณธ์ ์œผ๋กœ ๊ฑฐ๋ถ€ํ•œ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜, ๋ณดํ†ต ์„œ๋ฒ„์˜ endpoint์™€ ํ™ˆํŽ˜์ด์ง€ domain์€ ๋‹ค๋ฅธ ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๋‹ค.๋”ฐ๋ผ์„œ ์„œ๋ฒ„์—์„œ๋Š” ํ™ˆํŽ˜์ด์ง€ domain์„ ํ—ˆ์šฉํ•ด์„œ ๋‹ค๋ฅธ domain์ด๋ผ ํ•˜๋”๋ผ๋„ ์š”์ฒญ์„ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๊ฒŒ ํ•œ๋‹ค.
์„œ๋ฒ„๋Š” Access-Control-Allow-Origin ์™ธ์— Accsess-Control-์„ ํฌํ•จํ•˜๋Š” ํ—ค๋”์— CORS ๊ด€๋ จ ์ •๋ณด๋ฅผ ํด๋ผ์ด์–ธํŠธ๋กœ ๋ณด๋‚ธ๋‹ค.

same-origin policy

์›น์‚ฌ์ดํŠธ์— ์•…์„ฑ script๊ฐ€ ๋กœ๋“œ๋˜์–ด, ์ˆ˜์ƒํ•œ ์š”์ฒญ์„ ํ•˜๋Š” ๊ฒƒ์„ ๋ง‰๊ธฐ ์œ„ํ•จ์ด๋‹ค.
๋ฐ˜๋Œ€๋กœ, ์ต๋ช… ์œ ์ €๋กœ๋ถ€ํ„ฐ์˜ DDos๊ณต๊ฒฉ ๋“ฑ์„ ๋ง‰๊ธฐ ์œ„ํ•จ.
์„œ๋ฒ„์— ์ง์ ‘ CORS ์„ค์ •์„ ํ•  ์ˆ˜ ์—†๋‹ค๋ฉด, Proxy ์„œ๋ฒ„ ๋“ฑ์„ ๋งŒ๋“ค์–ด ํ•ด๊ฒฐํ•œ๋‹ค.

ํ•œ ์ค„ํ‰: ์ด๊ฑฐ์‹œ ๋ญ์‹œ๋‹ค๋ƒฅ.. ์ผ๋‹จ์€ ๋ฏธ๋ž˜์˜ ๋‚˜๋ฅผ ์œ„ํ•˜์—ฌ ์ •๋ฆฌํ•ด๋ณธ๋‹ค.

profile
์‚ฌ์šฉ์ž์˜ ํŽธ์˜๋ฅผ ๋” ์ƒ๊ฐํ•˜๊ณ  ํŽธ์•ˆํ•œ UI/UX ๊ฐœ๋ฐœ์„ ๊ฟˆ๊พธ๋Š” ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์ž ์ง€๋ง์ƒ์ž…๋‹ˆ๋‹ค.

0๊ฐœ์˜ ๋Œ“๊ธ€