Promise - JeongWu/fe-javascript GitHub Wiki

Promise

javascript engine

ex) Google V8(chrome, nodeJS)

  • Memory Heap: ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น
  • Call Stack: ์ฝ”๋“œ ์‹คํ–‰์— ๋”ฐ๋ผ ํ˜ธ์ถœ ์Šคํƒ์ด ์Œ“์ž„

runtime

  • web API: ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ œ๊ณตํ•˜๋Š” APIs
    ex) setTimeout
  • Event Loop: Callback Event Queue์—์„œ ํ•˜๋‚˜์”ฉ ๊บผ๋‚ด ๋™์ž‘์‹œํ‚ค๋Š” loop
  • Callback Queue: Event ์‹คํ–‰ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋˜๋Š” Queue

๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ

ํŠน์ • ์ฝ”๋“œ์˜ ์—ฐ์‚ฐ์ด ๋๋‚  ๋•Œ๊นŒ์ง€ ์ฝ”๋“œ์˜ ์‹คํ–‰์„ ๋ฉˆ์ถ”์ง€ ์•Š๊ณ  ๋‹ค์Œ ์ฝ”๋“œ๋ฅผ ๋จผ์ € ์‹คํ–‰

javascript ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ์ด์œ 

  • ๋‹จ์ผ ์Šค๋ ˆ๋“œ : ํ•œ์ˆœ๊ฐ„ ํ•˜๋‚˜์˜ ์ž‘์—…๋งŒ ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅ
  • ์—ฌ๋Ÿฌ๊ฐ€์ง€ event ์ฒ˜๋ฆฌํ•  ๋•Œ ๋™๊ธฐ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋ฉด ํ•˜๋‚˜์˜ event๊ฐ€ ๋ชจ๋‘ ์ฒ˜๋ฆฌ๋  ๋•Œ๊นŒ์ง€ ๋‹ค๋ฅธ ์–ด๋–ค ์—…๋ฌด๋„ ์ˆ˜ํ–‰X

ajax

function getData() {
	var tableData;
	$.get('https://domain.com/products/1', function(response) {
		tableData = response;
	});
	return tableData;
}

console.log(getData()); // undefined

setTimeount()

// #1
console.log('Hello');

// #2
setTimeout(function() {
	console.log('Bye');
}, 3000);

// #3
console.log('Hello Again');     //1,3,2

// setTimeout(callback, ms);
// ms == 0 ์ด๋ฉด ๋ฐ”๋กœ ์‹คํ–‰๋˜์ง€ ์•Š๊ณ  ์ตœ์†Œ ms ํ›„์— ์‹คํ–‰๋จ ๋‹ค์Œ event loop์— ์‹คํ–‰๋จ

setTimeout(function() {
    // (A)
    console.log('Second');
}, 0);
console.log('First');
// (B)

// First
// Second

promise

ES6์˜ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ ํŒจํ„ด

call back

function asyncFunction1(cb) {
  setTimeout(function() {
    console.log(1)
    cb()
  }, 1000)
}

function syncFunction1(cb) {
  console.log(1)
  cb()
}

function syncFunction2() {
  console.log(2)
}

asyncFunction1(function(asyncFunction1Result) {
  syncFunction1(function(syncFunction1Result) {
    syncFunction2()
  })
})
// 1 2 3

-> but call back hell ๋ฐœ์ƒ

function asyncFunction1(cb) {
  setTimeout(function() {
    console.log(1)
    cb()
  }, 100)
}

// ์ค‘๋žต

function asyncFunction9(cb) {
  setTimeout(function() {
    console.log(9)
    cb()
  }, 100)
}

function asyncFunction10(cb) {
  setTimeout(function() {
    console.log(10)
  }, 100)
}

asyncFunction1(function(result) {
  asyncFunction2(function(result) {
    asyncFunction3(function(result) {
      asyncFunction4(function(result) {
        asyncFunction5(function(result) {
          asyncFunction6(function(result) {
            asyncFunction7(function(result) {
              asyncFunction8(function(result) {
                asyncFunction9(function(result) {
                  asyncFunction10()
                })
              })
            })
          })
        })
      })
    })
  })
})

// 1 2 3 4 5 6 7 8 9 10

์ƒ์„ฑ

// Promise ๊ฐ์ฒด์˜ ์ƒ์„ฑ
const promise = new Promise((resolve, reject) => {
  // ๋น„๋™๊ธฐ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.

  if (/* ๋น„๋™๊ธฐ ์ž‘์—… ์ˆ˜ํ–‰ ์„ฑ๊ณต */) {
    resolve('result');
  }
  else { /* ๋น„๋™๊ธฐ ์ž‘์—… ์ˆ˜ํ–‰ ์‹คํŒจ */
    reject('failure reason');
  }
});

์ƒํƒœ

  • pending: ๋Œ€๊ธฐ์ค‘
  • fulfilled: ์ดํ–‰๋จ, ์„ฑ๊ณต๋ฆฌ์— ์™„๋ฃŒ
  • rejected: ์—ฐ์‚ฐ์ด ์‹คํŒจ

ํ›„์† ์ฒ˜๋ฆฌ ๋ฉ”์†Œ๋“œ

  • then: ์ฒซ ๋ฒˆ์งธ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋Š” ์„ฑ๊ณต ์‹œ ํ˜ธ์ถœ๋˜๊ณ  ๋‘ ๋ฒˆ์งธ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋Š” ์‹คํŒจ ์‹œ ํ˜ธ์ถœ
function get(url) {
    // Return a new promise.
    return new Promise(function(resolve, reject) {
        // Do the usual XHR stuff
        var req = new XMLHttpRequest();
        req.open('GET', url);
        req.onload = function() {
            // This is called even on 404 etc
            // so check the status
            if (req.status == 200) {
                // Resolve the promise with the response text
                resolve(req.response);
            } else {
                // Otherwise reject with the status text
                // which will hopefully be a meaningful error
                reject(Error(req.statusText));
            }
        }
        ;
    }
    );
}

get("https://jsonplaceholder.typicode.com/posts/1").then(resp=>console.log("resolve", resp), rej=>console.log("reject", rej), );

์—๋Ÿฌ ์ฒ˜๋ฆฌ ๋ฉ”์†Œ๋“œ

  • catch: ์˜ˆ์™ธ ๋ฐœ์ƒํ•˜๋ฉด ํ˜ธ์ถœ

์ฐจ์ด์ 

  • then: ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ์—์„œ ๋ฐœ์ƒํ•œ ์—๋Ÿฌ(reject ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ ๋œ ์ƒํƒœ)๋งŒ์„ ์บ์น˜
  • catch: ๋น„๋™๊ธฐ ์—๋Ÿฌ ๋ฟ ์•„๋‹ˆ๋ผ then ๋ฉ”์†Œ๋“œ ๋‚ด๋ถ€์—์„œ ๋ฐœ์ƒํ•œ ์—๋Ÿฌ

promise chain

ํ›„์† ์ฒ˜๋ฆฌ ๋ฉ”์†Œ๋“œ๋ฅผ ์ฒด์ด๋‹ํ•˜์—ฌ ์—ฌ๋Ÿฌ๊ฐœ์˜ ํ”„๋กœ๋ฏธ์Šค๋ฅผ ์—ฐ๊ฒฐํ•˜์—ฌ ์‚ฌ์šฉ

new Promise((resolve,reject)=>{
    console.log('Initial');
    resolve();
}
).then(()=>{
    throw new Error('Something failed');
    console.log('Do this');
}
).catch(()=>{
    console.log('Do that');
}
).then(()=>{
    console.log('Do this whatever happened before');
}
);
// Initial
// Do that
// Do this whatever happened before

์ •์  ๋ฉ”์†Œ๋“œ

  • Promise.resolve
    ์ฃผ์–ด์ง„ ๊ฐ’์œผ๋กœ resolveํ•˜๋Š” Promise๋ฅผ ์ƒ์„ฑ
const resolvedPromise = Promise.resolve([1, 2, 3]);
resolvedPromise.then(console.log); // [ 1, 2, 3 ]
  • Promise.reject
    ์ฃผ์–ด์ง„ ๊ฐ’์œผ๋กœ rejectํ•˜๋Š” promise๋ฅผ ์ƒ์„ฑ
const rejectedPromise = Promise.reject(new Error('Error!'));
rejectedPromise.catch(console.log); // Error: Error!
  • Promise.all
    ์ „๋‹ฌ๋ฐ›์€ ๋ชจ๋“  ํ”„๋กœ๋ฏธ์Šค๋ฅผ ๋ณ‘๋ ฌ๋กœ ์ฒ˜๋ฆฌํ•˜๊ณ  ๊ทธ ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ๋ฅผ resolveํ•˜๋Š” ์ƒˆ๋กœ์šด ํ”„๋กœ๋ฏธ์Šค๋ฅผ ๋ฐ˜ํ™˜
  • Promise.race
    ๊ฐ€์žฅ ๋จผ์ € ์ฒ˜๋ฆฌ๋œ ํ”„๋กœ๋ฏธ์Šค๊ฐ€ resolveํ•œ ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ๋ฅผ resolveํ•˜๋Š” ์ƒˆ๋กœ์šด ํ”„๋กœ๋ฏธ์Šค๋ฅผ ๋ฐ˜ํ™˜