Javascript , Promise ,

Javascript Promise

by Mimul FollowDecember 17, 2014 ยท 16 min read ยท Last Updated:
Share this

Javascript๋ฅผ ์‚ฌ์šฉํ•˜๋‹ค๋ณด๋ฉด ๋น„๋™๊ธฐ call ์š”์†Œ๋“ค์ด ๋งŽ์•„์„œ ๋กœ์ง์˜ ๊ฐ€๋…์„ฑ๊ณผ ์˜ค๋ฅ˜ ๋””๋ฒ„๊น… ๋ฌธ์ œ๋“ฑ์ด ๋ณต์žกํ•˜๊ฒŒ ์–ฝํžˆ๊ฒŒ ๋˜(์ด๋ฅผ ํ—ฌ์ด๋ผ๊ณ ๋„ ํ‘œํ˜„ํ•˜๋Š”๋ฐ), ์ด๋ฅผ ํšŒํ”ผํ•˜๊ธฐ ์œ„ํ•œ ๋ฐฉ๋ฒ•์ค‘์— ํ•˜๋‚˜๊ฐ€ Promise๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋Œ€๋ถ€๋ถ„ ๊ฒฝ์šฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ์ œ๊ณตํ•˜๊ณ  ์žˆ์–ด, ๊ทธ ๋‚ด์šฉ์„ ์ž˜ ๋ชจ๋ฅด๊ณ  ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์•„ ์˜ค์šฉ๋˜๋Š” ์‚ฌ๋ก€๋ฅผ ๊ฒฝํ—˜ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๋‚ด๋ถ€๋ฅผ ์ข€ ๋” ์ดํ•ดํ•˜๋Š”๋ฐ ๋„์›€์ด ๋˜๋Š” ์ข‹์€ ์•„ํ‹ฐํด์ด ์žˆ์–ด์„œ ๋ฒˆ์—ญ์„ ํ•ด๋ณด์•˜์Šต๋‹ˆ๋‹ค.

์†Œ๊ฐœ ์•„ํ‹ฐํด์€ JavaScript Promises ... In Wicked Detail ์ž…๋‹ˆ๋‹ค. ์ƒ์„ธํ•œ ๋‚ด์šฉ์€ ์•„๋ž˜๋ฅผ ๋”ฐ๋ผ๊ฐ€ ๋ณด์‹œ๋ฉด ๋  ๊ฑฐ ๊ฐ™๋„ค์š”.

์™œ Promise๊ฐ€ ํ•„์š”ํ•œ๊ฐ€?

์™œ Promise์— ๋Œ€ํ•ด์„œ ๋””ํ…Œ์ผํ•˜๊ฒŒ ์ดํ•ดํ•˜๋Š”๋ฐ ์‹ ๊ฒฝ์„ ์จ์•ผํ• ๊นŒ? ์‹ค์ œ Promise๊ฐ€ ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋Š”์ง€๋ฅผ ์•ˆ๋‹ค๋Š” ๊ฒƒ์€ ๊ทธ๊ฒƒ์„ ํ™œ์šฉํ•˜๋Š” ๋Šฅ๋ ฅ์ด ํ–ฅ์ƒ๋˜๊ณ  ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ์—๋„ ๋” ์„ฑ๊ณต์ ์œผ๋กœ ๋””๋ฒ„๊น…์„ ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ด ์•„ํ‹ฐํด์„ ์“ฐ๊ฒŒ๋œ ๊ณ„๊ธฐ๋Š” ๋™๋ฃŒ์™€ ๋‚ด๊ฐ€ Promise์˜ ๊นŒ๋‹ค๋กœ์šด ๊ฒฝ์šฐ๋ฅผ ์ ‘ํ•ด์„œ ๊ณ ์ƒํ•œ ์ ์ด ์žˆ์—ˆ๋‹ค. ์ง€๊ธˆ Promise์— ๋Œ€ํ•ด ์•Œ์•˜๋˜ ๊ฒƒ์„ ๊ทธ ๋•Œ๋„ ์•Œ์•˜๋”๋ผ๋ฉด ๊ณ ์ƒ์„ ๋œ ํ–ˆ์„ ์ˆ˜ ์žˆ์—ˆ์„ ๊ฒƒ์ด๋‹ค.

์‹ฌํ”Œํ•œ ์‚ฌ์šฉ ์‚ฌ๋ก€

๋จผ์ € ๊ฐ€์žฅ ๊ฐ„๋‹จํ•œ Promise์— ๋Œ€ํ•œ ๊ตฌํ˜„์„ ์‚ดํŽด๋ณด์ž. ๋‹ค์Œ ํ•จ์ˆ˜๊ฐ€ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•œ๋‹ค.

doSomething(function(value) {
  console.log('Got a value:' + value);
});

์ด ํ•จ์ˆ˜๋ฅผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‚ฌ์šฉํ•˜๋ ค ํ•œ๋‹ค.

doSomething().then(function(value) {
  console.log('Got a value:' + value);
});

์œ„์ฒ˜๋Ÿผ ํ•˜๊ธฐ ์œ„ํ•ด doSomething()์—์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ถ€๋ถ„์„ ๋ณ€๊ฒฝํ•ด์•ผ ํ•œ๋‹ค.

function doSomething(callback) {
  var value = 42;
  callback(value);
}

๋‹ค์Œ๊ณผ ๊ฐ™์ด Promise ๊ธฐ๋ฐ˜์œผ๋กœ ๋ณ€๊ฒฝํ•œ๋‹ค.

function doSomething() {
  return {
    then: function(callback) {
      var value = 42;
      callback(value);
    }
  };
}

์‹คํ–‰ ํ™”๋ฉด : Fiddle

์ด ๊ตฌํ˜„์€ Callback ํŒจํ„ด์˜ ๋‹จ์ˆœํ•œ ๋Œ€์ฒด์ด๋ฉฐ, ์ด๊ฒƒ๋งŒ์œผ๋กœ๋Š” ํฐ ์˜๋ฏธ๊ฐ€ ๋˜์ง€ ์•Š๋Š”๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์•„์ฃผ ๊ฐ„๋‹จํ•œ ๊ตฌํ˜„์ด์—ˆ์ง€๋งŒ, Promise์˜ ํ•ต์‹ฌ์ ์ธ ์•„์ด๋””์–ด๋ฅผ ์ด๋ฏธ ์ดํ•ดํ–ˆ๋‹ค๊ณ  ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

Promise๋Š” ๊ฐ์ฒด์•ˆ์— ๊ถ๊ทน์ ์œผ๋กœ ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ๊ฐ’๋ฅผ ์ˆ˜์ง‘ํ•œ๋‹ค.

์ด์ ์—์„œ Promise๊ฐ€ ๋งค์šฐ ํฅ๋ฏธ๋กญ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋Š” ํฐ ์ด์œ ์ด๋‹ค. ์ผ๋‹จ Promise ๋‚ด์— ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ๊ฐ€ ์ˆ˜์ง‘๋˜๋ฉด, ๊ทธ ๋‹ค์Œ์€ ๋งค์šฐ ๊ฐ•๋ ฅํ•˜๊ฒŒ ์ผ์„ ์ง„ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ์ ์— ๋Œ€ํ•ด์„œ๋Š” ์ข€ ๋” ๋‚˜์ค‘์— ์„ค๋ช…ํ•œ๋‹ค.

Promise ํƒ€์ž… ์ •์˜

์œ„์˜ ๊ฐ„๋‹จํ•œ ๊ฐ์ฒด ๋ฆฌํ„ฐ๋Ÿด ๊ตฌํ˜„์€ ์ž˜ ๋Œ์•„๊ฐ€์ง€ ์•Š์„ ๊ฒƒ์ด๋‹ค. ์šฐ๋ฆฌ๋Š” ์•ž์œผ๋กœ ์ž˜ ์„ค๋ช…ํ•˜๊ธฐ ์œ„ํ•ด, Promise ํด๋ž˜์Šค๋ฅผ ์ •์˜ํ•œ๋‹ค.

function Promise(fn) {
  var callback = null;
  this.then = function(cb) {
    callback = cb;
  };

  function resolve(value) {
    callback(value);
  }

  fn(resolve);
}

์ด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ doSomething()์„ ์žฌ๊ตฌํ˜„ํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋œ๋‹ค.

function doSomething() {
  return new Promise(function(resolve) {
    var value = 42;
    resolve(value);
  });
}

๊ทธ๋Ÿฐ๋ฐ, ์—ฌ๊ธฐ์—๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค. ์‹คํ–‰ํ•ด์„œ ์ถ”์ ํ•˜๋ฉด resolve()๊ฐ€ then()๋ณด๋‹ค ๋จผ์ € ํ˜ธ์ถœ๋˜๊ณ  ๊ทธ ๊ฒฐ๊ณผ callback์€ null์ด ๋œ๋‹ค. ์ด ๋ฌธ์ œ์— ๋Œ€์‘ํ•˜๊ธฐ ์œ„ํ•ด setTimeout์„ ์‚ฌ์šฉ(ํ•ดํ‚น ์œ„ํ˜‘์ด ์žˆ์ง€๋งŒ)ํ•œ๋‹ค.

function Promise(fn) {
  var callback = null;
  this.then = function(cb) {
    callback = cb;
  };

  function resolve(value) {
    // force callback to be called in the next
    // iteration of the event loop, giving
    // callback a chance to be set by then()
    setTimeout(function() {
      callback(value);
    }, 1);
  }

  fn(resolve);
}

์‹คํ–‰ ํ™”๋ฉด : Fiddle

์ด ์ฝ”๋“œ๋Š” ๋ฌธ์ œ๊ฐ€ ๋  ์†Œ์ง€๊ฐ€ ๋งŽ์€ ์ข‹์ง€ ์•Š์€ ์ฝ”๋“œ์ด๋‹ค.

์ด Promise์˜ ์ทจ์•ฝ์„ฑ์ด ๋งŽ์€ ์ฝ”๋“œ๋ฅผ ์ œ๋Œ€๋กœ ๋™์ž‘์‹œํ‚ค๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์•ผํ•œ๋‹ค. ์ด ๊ตฌํ˜„์—์„œ ์˜ค๋ฅ˜๋ฅผ ์œ ๋ฐœ์‹œํ‚ค๋Š” ๊ฒƒ์€ ๊ฐ„๋‹จํ•ด์„œ then()์„ ๋น„๋™๊ธฐ์ ์œผ๋กœ ํ˜ธ์ถœํ•˜๋ผ. ๊ทธ๋Ÿฐ ํ›„ ๋‹ค์‹œ callback์€ null์ด ๋œ๋‹ค. ์™œ ์ด๋ ‡๊ฒŒ ์ทจ์•ฝํ•œ ์ฝ”๋“œ๋ฅผ ์„ค์ •ํ–ˆ์„๊นŒ? ์œ„์˜ ๊ตฌํ˜„์€ ์•„์ฃผ ์ดํ•ดํ•˜๊ธฐ ์‰ฝ๋‹ค๋Š” ์ž‡์ ์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์œ„์™€ ๊ฐ™์€ ๊ฐ„๋‹จํ•œ ๊ตฌํ˜„์„ ํ†ตํ•ด Promise์—์„œ ์ค‘์š”ํ•œ then()๊ณผ resolve()๋ฅผ ๋ช…ํ™•ํ•˜๊ฒŒ ์•Œ ์ˆ˜ ์žˆ๋‹ค. then()๊ณผ resolve()๋Š” Promise์—์„œ ์ค‘์š”ํ•œ ๊ฐœ๋…์ด๋‹ค.

Promise๊ฐ€ ์ƒํƒœ๋ฅผ ๊ฐ€์ง„๋‹ค.

์šฐ๋ฆฌ์˜ ์–ด์„คํ”ˆ ์ฝ”๋“œ๋Š” ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ๊ฒƒ๋“ค์„ ๋ฐœ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋ž˜์„œ Promise๋Š” ์ƒํƒœ๋ฅผ ๊ฐ–๋Š”๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ์šฐ๋ฆฌ๋Š” ํ”„๋กœ์„ธ์Šค๋ฅผ ์ง„ํ–‰ํ•˜๊ธฐ ์ „์— Promise๊ฐ€ ์–ด๋–ค ์ƒํƒœ์ธ์ง€๋ฅผ ์•Œ ํ•„์š”๊ฐ€ ์žˆ๊ณ , ๊ทธ๋ฆฌ๊ณ  ๊ทธ ์ƒํƒœ๊ฐ€ ์–ด๋–ป๊ฒŒ ์ด๋™ํ•˜๊ณ  ์žˆ๋Š”์ง€๋ฅผ ์ •ํ™•ํžˆ ์•Œ์•„์•ผ ํ•œ๋‹ค. ์ด์ œ ์ฝ”๋“œ์˜ ์ทจ์•ฝ์„ฑ ๋ถ€๋ถ„์„ ์—†์• ์ž.

  • Promise๋Š” ๊ฐ’์ด ํ™•์ •๋  ๋•Œ๊นŒ์ง€ pending ์ƒํƒœ์—๋กœ ์œ ์ง€๋˜์—ˆ๋‹ค๊ฐ€ ๊ฐ’์ด ๊ฒฐ์ •๋˜๋ฉด resolved์ƒํƒœ๊ฐ€ ๋œ๋‹ค.
  • ์ผ๋‹จ ๊ฐ’์ด resolved๋˜๋ฉด ํ•ญ์ƒ ๊ทธ ๊ฐ’์„ ์œ ์ง€ํ•˜๊ณ  ๋‹ค์‹œ ํ™•์ธ์„ ํ•˜์ง€ ์•Š๋Š”๋‹ค.

(Promise์—๋Š” rejected๋ผ๋Š” ์ƒํƒœ๋„ ์žˆ์ง€๋งŒ, ๋‚˜์ค‘์— ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ ๋•Œ ๋‹ค์‹œ ์„ค๋ช…ํ•œ๋‹ค.)

ํ•ดํ‚น์˜ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋Š” setTimeout์„ ์—†์• ๊ณ  ๊ตฌํ˜„์ฒด ๋‚ด๋ถ€์˜ ์ƒํƒœ ๋ณ€ํ™”๋ฅผ ์ถ”์ ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด๋ณด์ž.

function Promise(fn) {
  var state = 'pending';
  var value;
  var deferred;

  function resolve(newValue) {
    value = newValue;
    state = 'resolved';

    if(deferred) {
      handle(deferred);
    }
  }

  function handle(onResolved) {
    if(state === 'pending') {
      deferred = onResolved;
      return;
    }

    onResolved(value);
  }

  this.then = function(onResolved) {
    handle(onResolved);
  };

  fn(resolve);
}

์‹คํ–‰ ํ™”๋ฉด : Fiddle

์กฐ๊ธˆ ๋ณต์žกํ•˜์ง€๋งŒ ํ˜ธ์ถœ์ž(ํ˜ธ์ถœํ•˜๋Š” ์ธก)๋Š” ์›ํ•˜๋Š” ์‹œ๊ฐ„์— then()์„ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ํ”ผํ˜ธ์ถœ์ž(ํ˜ธ์ถœ๋˜๋Š” ์ชฝ)๋Š” ์–ธ์ œ๋“ ์ง€ resolve()๋ฅผ ๋ถ€๋ฅผ ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค. ๋™๊ธฐ๋‚˜ ๋น„๋™๊ธฐ ์ƒํ™ฉ์—์„œ๋„ ์™„๋ฒฝํ•˜๊ฒŒ ๋™์ž‘ํ•˜๊ณ  ์žˆ๋‹ค.

์ด๋ ‡๊ฒŒ ๋œ ์ด์œ ๋Š” state ํ”Œ๋ž˜๊ทธ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. then()๊ณผ resolve() ๋‘˜ ๋‹ค ์ƒˆ๋กœ์šด ํ•จ์ˆ˜์ธ handle()์— ์ฒ˜๋ฆฌ๋ฅผ ์œ„์ž„ํ•œ๋‹ค. handle()์€ ์ƒํ™ฉ์— ๋”ฐ๋ผ ๋‘๊ฐ€์ง€ ์ž‘์—…์„ ๊ตฌ๋ถ„ํ•œ๋‹ค.

  • ํ”ผํ˜ธ์ถœ์ž resolve()๋ฅผ ์‹คํ–‰ํ•˜๊ธฐ ์ „์— ํ˜ธ์ถœ์ž๊ฐ€ then()์„ ์‹คํ–‰ํ•˜๋ฉด ๊ฐ’์„ ๋Œ๋ ค์ค„ ์ค€๋น„๊ฐ€ ๋˜์ง€ ์•Š์€ ์ƒํƒœ์ด๋‹ค. ์ด๋Ÿฌํ•œ ๊ฒฝ์šฐ state๋Š” pending ์ƒํƒœ๊ฐ€ ๋  ๊ฒƒ์ด๊ณ  ํ˜ธ์ถœ์ž๊ฐ€ ์ง€์ •ํ•œ callack์ด ๋‚˜์ค‘์— ์‚ฌ์šฉ๋ ๋•Œ๊นŒ์ง€ ์œ ์ง€๋œ๋‹ค. ๊ทธ๋Ÿฐ ํ›„ resolve()๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉด callback์ด ์‹คํ–‰๋˜๊ณ  ํ˜ธ์ถœ์ž์—๊ฒŒ ๊ฐ’์„ ์ „๋‹ฌํ•œ๋‹ค.
  • ํ˜ธ์ถœ์ž๊ฐ€ then()์„ ํ˜ธ์ถœํ•˜๊ธฐ ์ „์— ํ”ผํ˜ธ์ถœ์ž๊ฐ€ resolve()๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ๊ฐ’์€ ํ™•์ •๋œ ์ƒํƒœ๊ฐ€ ๋œ๋‹ค. ์ด ๊ฒฝ์šฐ then()์ด ํ˜ธ์ถœ๋˜๋ฉด ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•  ์ค€๋น„๋ฅผ ํ•œ๋‹ค.

์ฃผ๋ชฉํ•  ๊ฒƒ์€ setTimeout์˜ ๊ตฌํ˜„์ฒด๋Š” ์—†์–ด์กŒ์ง€๋งŒ, ๊ทธ๊ฒƒ์€ ์ผ์‹œ์ ์ด๊ณ  ๋‚˜์ค‘์— ๋‹ค์‹œ ๋‚˜ํƒ€๋‚œ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๊ทธ ๋•Œ ์„ค๋ช…ํ•œ๋‹ค.

Promise๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด then()๊ณผ resolve()์˜ ํ˜ธ์ถœ ์ˆœ์„œ๋ฅผ ๊ณ ๋ คํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค. then()๊ณผ resolve()๋Š” ์šฐ๋ฆฌ์˜ ์ด์šฉ ๋ชฉ์ ์— ๋”ฐ๋ผ ์–ธ์ œ๋ผ๋„ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๊ฒƒ์€ Promise ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ๊ฐ’๋ฅผ ๊ฐ์ฒด์— ์ €์žฅํ•˜๋Š” ๋ฐ ์•„์ฃผ ํฐ ์žฅ์  ์ค‘์— ํ•˜๋‚˜๋‹ค.

์šฐ๋ฆฌ๊ฐ€ ๊ตฌํ˜„ํ•ด์•ผ ํ•  ์ŠคํŽ™์•ˆ์—๋Š” ์•„์ฃผ ๋งŽ์€ ์ผ์ด ์žˆ์ง€๋งŒ, ์šฐ๋ฆฌ์˜ Promise ์ด๋ฏธ ํŒŒ์›Œํ’€ํ•˜๋‹ค. ์ด ๊ตฌํ˜„์ฒด๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด then()๋ฅผ ์›ํ•˜๋Š” ๋งŒํผ ์—ฌ๋Ÿฌ ๋ฒˆ ํ˜ธ์ถœํ•ด๋„ ํ•ญ์ƒ ๊ฐ™์€ ๊ฐ’์„ ๋Œ๋ ค๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค.

var promise = doSomething();

promise.then(function(value) {
  console.log('Got a value:', value);
});

promise.then(function(value) {
  console.log('Got the same value again:', value);
});

์ด ์•„ํ‹ฐํด์—์„œ ๊ตฌํ˜„ํ•œ Promise๋Š” ์™„๋ฒฝํ•˜์ง€๋Š” ์•Š๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ๋งŒ์•ฝ resolve()๊ฐ€ ํ˜ธ์ถœ๋˜๊ธฐ ์ „์— ์—ฌ๋Ÿฌ ๋ฒˆ then()์„์— ํ˜ธ์ถœํ•˜๋ฉด ๋งˆ์ง€๋ง‰์— ํ˜ธ์ถœํ•œ then()๋งŒ ์‚ฌ์šฉ๋œ๋‹ค. ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•œ ํ•œ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์€ callback์„ ๋ฐฐ์—ด๋กœ ์œ ์ง€(deferreds)ํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์—ฌ๊ธฐ์—์„œ๋Š” ๊ตฌํ˜„์€ ์•Š๊ณ  Promise์˜ ๊ฐœ๋…์„ ์†Œ๊ฐœํ•˜๋Š”๋ฐ ์ฝ”๋“œ๋ฅผ ๊ฐ€๋Šฅํ•œ ํ•œ ๋‹จ์ˆœํ•˜๊ฒŒ ํ•˜๋ ค๋Š” ๋ชฉ์ ์ด ์žˆ๋‹ค. ์ง€๊ธˆ๊นŒ์ง€ ๊ตฌํ˜„์œผ๋กœ๋„ Promise๋ฅผ ์„ค๋ช…ํ•˜๊ธฐ ์œ„ํ•ด ์ถฉ๋ถ„ํ•˜๋‹ค.

Promise ๋ฉ”์†Œ๋“œ ์ฒด์ธ

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

getSomeData()
.then(filterTheData)
.then(processTheData)
.then(displayTheData);

getSomeData()๋Š” ์ฆ‰์‹œ then() ํ˜ธ์ถœ์ด ๋˜์—ˆ๋Š”์ง€ ์•Œ ์ˆ˜ ์žˆ์–ด์„œ ํ•ด๋‹น Promise๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜, ์ฒซ๋ฒˆ์งธ then()์˜ ํ˜ธ์ถœ ๊ฒฐ๊ณผ๋„ Promise๋ฉฐ, ๊ทธ ๋ฐ˜ํ™˜๊ฐ’์„ ์‚ฌ์šฉํ•ด ๋‹ค์Œ then()์„ ํ˜ธ์ถœํ•œ๋‹ค.(๊ทธ ๋‹ค์Œ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๋‹ค). then()์—์„œ Promise๋ฅผ ๋ฐ˜ํ™˜ํ•˜์—ฌ ๋ฌด์Šจ์ผ์ด ์ผ์–ด๋‚˜๋Š”์ง€ ์•Œ์ˆ˜ ์žˆ์–ด ๋” ๋งŽ์€ ์ •๋ณด๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๊ฒƒ์ด ๋ฉ”์†Œ๋“œ ์ฒด์ธ์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

then()์€ ๋ฐ˜๋“œ์‹œ Promise๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

์—ฌ๊ธฐ์„œ ์šฐ๋ฆฌ Promise ํด๋ž˜์Šค์™€ ํ•จ๊ป˜ ๋ฉ”์†Œ๋“œ ์ฒด์ธ์„ ์ถ”๊ฐ€ํ•˜์ž.

function Promise(fn) {
  var state = 'pending';
  var value;
  var deferred = null;

  function resolve(newValue) {
    value = newValue;
    state = 'resolved';

    if(deferred) {
      handle(deferred);
    }
  }

  function handle(handler) {
    if(state === 'pending') {
      deferred = handler;
      return;
    }

    if(!handler.onResolved) {
      handler.resolve(value);
      return;
    }

    var ret = handler.onResolved(value);
    handler.resolve(ret);
  }

  this.then = function(onResolved) {
    return new Promise(function(resolve) {
      handle({
        onResolved: onResolved,
        resolve: resolve
      });
    });
  };

  fn(resolve);
}

์‹คํ–‰ ํ™”๋ฉด : Fiddle

ํœด. ์•ฝ๊ฐ„ ์ฝ”๋“œ๊ฐ€ ์กฐ๊ธˆ ๋ณต์žกํ•ด์กŒ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ์ฒœ์ฒœํžˆ ๊ตฌ์ถ•ํ•˜๋Š” ๊ฒƒ์ด ๊ธฐ์˜์ง€ ์•„๋‹ˆํ•œ๊ฐ€? ์—ฌ๊ธฐ์„œ ์ค‘์š”ํ•œ ํ‚ค๋Š” then()์ด ์ƒˆ๋กœ์šด Promise๋ฅผ ๋ฐ˜ํ™˜ํ–ˆ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

then()์€ ํ•ญ์ƒ ์ƒˆ๋กœ์šด Promise๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํ•˜๋‚˜ ์ด์ƒ์˜ ์—ฌ๋Ÿฌ Promise๊ฐ์ฒด(created, resolved, ignored ๋˜๋Š”)๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค. ์ด๊ฒƒ์€ ๊ฐ์ฒด์˜ ๋‚ญ๋น„์ฒ˜๋Ÿผ ๋ณด์ผ์ˆ˜ ์žˆ๋‹ค. Callback ๊ธฐ๋ฒ•์—์„œ๋Š” ์ด๊ฒƒ์€ ๋ฌธ์ œ๊ฐ€ ๋˜์ง€ ์•Š๋Š”๋‹ค. ๋‹ค๋ฅธ ํ•œํŽธ์œผ๋กœ Promise๊ฐ€ ๋น„ํŒ์„ ๋ฐ›์„ ์ˆ˜ ์žˆ๋Š” ์ค‘์š”ํ•œ ์š”์†Œ๊ฐ€ ๋œ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋ช‡๋ช‡ JavaScript ์ปค๋ฎค๋‹ˆํ‹ฐ์—์„œ๋Š” ์ด๋Ÿฐ ์ ์œผ๋กœ ์ธํ•ด Promise๋ฅผ ๊บผ๋ฆฌ๋Š” ํ˜•ํƒœ๋ฅผ ์ทจํ•˜์ง€ ์•Š๊ณ , ์ œ๋Œ€๋กœ ์ ‘๊ทผํ•˜๊ธฐ ์‹œ์ž‘ํ–ˆ๋‹ค.

๋‘๋ฒˆ์งธ Promise๊ฐ€ ํ•ด๊ฒฐํ•ด์•ผํ•˜๋Š” ๊ฒƒ์€ ๋ฌด์—‡์ธ๊ฐ€? ๊ทธ๊ฒƒ์€ ์ฒซ๋ฒˆ์งธ Promise๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฐ’์„ ๋ฐ›๋Š” ๊ฒƒ์ด๋‹ค. ์ฆ‰,๋‘๋ฒˆ์งธ Promise๋Š” ์ฒซ๋ฒˆ์งธ ๋ฐ˜ํ™˜ ๊ฐ’์„ ์ธ์ˆ˜๋กœ ๋ฐ›๋Š”๋‹ค. ์ด๊ฒƒ์€ handle() ํ›„๋ฐ˜ ๋ถ€๋ถ„์— ๊ตฌํ˜„๋˜์–ด ์žˆ์œผ๋ฉฐ, handler ๊ฐ์ฒด๋Š” resolve()์— ๋Œ€ํ•œ ์ฐธ์กฐ์™€ onResolved์˜ callback์— ๋Œ€ํ•œ ์ฐธ์กฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค. ๊ฑฐ๊ธฐ์—๋Š” resolve()์˜ ๋ณต์‚ฌ๋ณธ์„ ๊ฐ€์ง€๊ณ  ์žˆ๊ณ  ๊ฐ Promise๋“ค์€ ์ž์‹ ์˜ resolve()๋ฅผ ๋ณต์‚ฌํ•˜๊ฑฐ๋‚˜ ๋‚ด๋ถ€์—์„œ ์‹คํ–‰ ํด๋กœ์ €๋ฅผ ๊ฐ–๋Š”๋‹ค. ์ด๊ฒƒ์ด ์ฒซ๋ฒˆ์งธ Promise์™€ ๋‘๋ฒˆ์งธ Promise์˜ ๋‹ค๋ฆฌ๋‹ค. ์ฒซ๋ฒˆ์งธ Promise๋ฅผ ๋‹ค์Œ ์ฝ”๋“œ์—์„œ ํ•ด๊ฒฐํ•œ๋‹ค.

var ret = handler.onResolved(value);

์ด ์˜ˆ์ œ์—์„œ๋Š” handler.onResolved๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

function(value) {
  console.log("Got a value:", value);
}

๋‹ค๋ฅด๊ฒŒ ๋งํ•˜๋ฉด, ์–ด์ฐŒํ•˜๋ฉด ์ด๊ฒƒ์ด ์ฒซ๋ฒˆ์งธ ํ˜ธ์ถœ๋กœ then()์— ์ „๋‹ฌ๋˜๋Š” ํ”„๋กœ์„ธ์Šค๋‹ค. ์ฒซ๋ฒˆ์งธ handler ๋ฐ˜ํ™˜ ๊ฐ’์ด ๋‘๋ฒˆ์งธ Promise๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋œ๋‹ค. ์ด์ œ ๋ฉ”์†Œ๋“œ ์ฒด์ธ ๊ตฌํ˜„์ด ์™„์„ฑ๋˜์—ˆ๋‹ค.

doSomething().then(function(result) {
  console.log('first result', result);
  return 88;
}).then(function(secondResult) {
  console.log('second result', secondResult);
});
// the output is
//
// first result 42
// second result 88

doSomething().then(function(result) {
  console.log('first result', result);
  // not explicitly returning anything
}).then(function(secondResult) {
  console.log('second result', secondResult);
});
// now the output is
//
// first result 42
// second result undefined

then()์€ ํ•ญ์ƒ ์ƒˆ๋กœ์šด Promise๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์›ํ•˜๋Š”๋งŒํผ ๋ฉ”์†Œ๋“œ ์ฒด์ธ์„ ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.

doSomething().then(function(result) {
  console.log('first result', result);
  return 88;
}).then(function(secondResult) {
  console.log('second result', secondResult);
  return 99;
}).then(function(thirdResult) {
  console.log('third result', thirdResult);
  return 200;
}).then(function(fourthResult) {
  // on and on...
});

๋งŒ์•ฝ ์œ„์˜ ์ฝ”๋“œ์—์„œ ๋งˆ์ง€๋ง‰์—์„œ ๋ชจ๋“  ์ฒ˜๋ฆฌ์˜ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ์—๋Š” ์–ด๋–ป๊ฒŒํ•˜๋ฉด ๋ ๊นŒ? ๋ฉ”์†Œ๋“œ ์ฒด์ธ์„ ์‚ฌ์šฉํ•˜์—ฌ ํ•„์š”์— ๋”ฐ๋ผ ์šฐ๋ฆฌ ์Šค์Šค๋กœ๊ฐ€ ๊ฒฐ๊ณผ๋ฅผ ๋งค๋‰ด์–ผํ•˜๊ฒŒ ์ „๋‹ฌํ•  ํ•„์š”๊ฐ€ ์žˆ๋‹ค.

doSomething().then(function(result) {
  var results = [result];
  results.push(88);
  return results;
}).then(function(results) {
  results.push(99);
  return results;
}).then(function(results) {
  console.log(results.join(', ');
});

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

Promise๋ฅผ ๋” ์ž˜ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ๋Š” Promise ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ all() ๋ฉ”์†Œ๋“œ๋‚˜, ๋งŽ์€ ๋‹ค๋ฅธ Utility ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด Promise์˜ ์œ ์šฉ์„ฑ์„ ๋” ์ข‹์•„์ง„๋‹ค. ๋ฌด์—‡์„ ์‚ฌ์šฉ ํ•˜๋Š”๊ฐ€๋Š” ๋…์ž ์—ฌ๋Ÿฌ๋ถ„์˜ ์ทจํ–ฅ์— ๋งž๊ฒŒ ์„ ํƒํ•˜๋ฉด ๋œ๋‹ค.

Callback์€ ์„ ํƒ์‚ฌํ•ญ์ด๋‹ค.

then()์— ์ง€์ •๋œ callback์€ ์—„๋ฐ€ํžˆ ํ•„์ˆ˜ ์‚ฌํ•ญ์€ ์•„๋‹ˆ๋‹ค. ๋งŒ์•ฝ callback์„ ์—†์•ด์„ ๊ฒฝ์šฐ Promise๋Š” ์ด์ „ Promise๊ณผ ๊ฐ™์€ ๊ฐ’์„ ์ฒ˜๋ฆฌํ•ด ์ค€๋‹ค.

doSomething().then().then(function(result) {
  console.log('got a result', result);
});

// the output is
//
// got a result 42

์ด๋ฏธ ๊ตฌํ˜„๋œ handle()์˜ ๋‚ด์šฉ์„ ๋ณด๋ฉด callack์ด ์—†๋Š” ๊ฒฝ์šฐ์—๋Š” Promise๋ฅผ resolveํ•˜๊ณ  ์ฒ˜๋ฆฌ๋ฅผ ์ข…๋ฃŒํ•˜๋„๋ก ๋˜์–ด์žˆ๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

if(!handler.onResolved) {
  handler.resolve(value);
  return;
}

๋ฉ”์†Œ๋“œ ์ฒด์ธ ๋‚ด์—์„œ Promise ๋ฐ˜ํ™˜

์šฐ๋ฆฌ์˜ ์ฒด์ธ ๊ตฌํ˜„ ๋ฐฉ๋ฒ•์€ ์•ฝ๊ฐ„ ์ •๊ตํ•˜์ง€ ๋ชปํ•œ ๋ถ€๋ถ„์ด ์žˆ๋‹ค. ์šฐ๋ฆฌ์˜ resolve๋œ ๊ฐ’์— ๋Œ€ํ•ด ์•„๋ฌด๊ฒƒ๋„ ํ™•์ธํ•˜์ง€ ์•Š๊ณ  ๋‹ค์Œ ์ž‘์—…์— ๊ทธ๋Œ€๋กœ ์ „๋‹ฌํ•œ๋‹ค. ๋งŒ์•ฝ resolve๋œ ๊ฐ’ ํ•˜๋‚˜๊ฐ€ Promise ๊ฐ์ฒด์ด๋ผ๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ์š”? ์˜ˆ๋ฅผ ๋“ค์–ด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒฝ์šฐ์ด๋‹ค.

doSomething().then(result) {
  // doSomethingElse returns a promise
  return doSomethingElse(result)
}.then(function(finalResult) {
  console.log("the final result is", finalResult);
});

์ด ์ฝ”๋“œ๋Š” ์šฐ๋ฆฌ๊ฐ€ ์›ํ•˜๋Š” ๋Œ€๋กœ ์›€์ง์ด์ง€ ์•Š๋Š”๋‹ค. finalResult์—๋Š” resolve๋œ ๊ฐ’์ด ์•„๋‹ˆ๋ผ Promise ๊ฐ์ฒด๊ฐ€ ์ „๋‹ฌ๋œ๋‹ค. ์˜๋„๋œ ๊ฒฐ๊ณผ๊ฐ’์„ ์–ป๊ธฐ์œ„ํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ตฌํ˜„์„ ์ˆ˜์ •ํ•ด์•ผ ํ•œ๋‹ค.

doSomething().then(result) {
  // doSomethingElse returns a promise
  return doSomethingElse(result)
}.then(function(anotherPromise) {
  anotherPromise.then(function(finalResult) {
    console.log("the final result is", finalResult);
  });
});

์ฝ”๋“œ๊ฐ€ ๊ฝค ๋ณต์žกํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค. ์ด ์†”๋ฃจ์…˜์€ Promise์˜ ๊ตฌํ˜„์„ ๋ณ€๊ฒฝํ•˜์—ฌ resolve๋œ ๊ฐ’์ด Promise ๊ฐ์ฒด์ธ์ง€ ํ˜ธ์ถœ์ž๊ฐ€ ์˜์‹ํ•˜์ง€ ์•Š๊ณ  ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค. ์ด๊ฒƒ์€ ์‰ฝ๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ resolve()์— ์ „๋‹ฌ ๋œ ๊ฐ’์ด Promise๊ฐ์ฒด์ธ ๊ฒฝ์šฐ์— ํŠน๋ณ„ํ•œ ์ฒ˜๋ฆฌ๊ฐ€ ์ถ”๊ฐ€๋˜์—ˆ์„ ๋ฟ์ด๋‹ค.

function resolve(newValue) {
  if(newValue && typeof newValue.then === 'function') {
    newValue.then(resolve);
    return;
  }
  state = 'resolved';
  value = newValue;

  if(deferred) {
    handle(deferred);
  }
}

์‹คํ–‰ ํ™”๋ฉด : Fiddle

Promise๋ฅผ ์ˆ˜์‹ ํ–ˆ์„ ๊ฒฝ์šฐ resolve()๋ฅผ ์žฌ๊ท€์ ์œผ๋กœ ๊ณ„์† ํ˜ธ์ถœํ•˜๊ฒŒ ๋œ๋‹ค. ํƒ€์ž…์ด Promise๊ฐ€ ์•„๋‹ˆ๋ฉด ๊ทธ ์‹œ์ ์—์„œ ์ฒ˜๋ฆฌ๋ฅผ ๋‹ค์Œ์œผ๋กœ ์ง„ํ–‰ํ•œ๋‹ค.

์ด๋Ÿฐ ๊ฒฝ์šฐ์—๋Š” ๋ฌดํ•œ ๋ฃจํ”„๊ฐ€ ๋  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋‹ค. Promise/A+ ์ŠคํŽ™์€ ํ•„์ˆ˜ ์‚ฌํ•ญ์€ ์•„๋‹ˆ์ง€๋งŒ ๋ฌดํ•œ ๋ฃจํ”„๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋Š” ํ˜•ํƒœ๋กœ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•˜๊ณ  ์žˆ๋‹ค.

๋˜ํ•œ ์—ฌ๊ธฐ์—์„œ ์†Œ๊ฐœํ•˜๋Š” ๊ตฌํ˜„์ฒด๋Š” ์ŠคํŽ™์„ ์ถฉ์กฑํ•˜์ง€๋Š” ์•Š์•˜๋‹ค. ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์ด ์•„ํ‹ฐํด์—์„œ ์†Œ๊ฐœํ•œ ๊ตฌํ˜„์ฒด๋„ ์ŠคํŽ™์„ ์ถฉ์กฑํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์— ๋”ํ•ด ์ข€ ๋” ํ˜ธ๊ธฐ์‹ฌ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๋ฉด Promise resolution procedure๋ฅผ ์ฝ๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•œ๋‹ค.

์ฃผ๋ชฉํ• ๋งŒํ•œ ๊ฑด, newValue๊ฐ€ Promise๊ฐ์ฒด์ธ์ง€ ์—ฌ๋ถ€์˜ ํŒ์ •์ด ๋Š์Šจํ•˜๊ฒŒ ์ฒดํฌ๋ฅผ ํ•˜๋Š” ๊ฑด ์•„๋‹๊นŒ? ์—ฌ๊ธฐ์„  then() ํ•จ์ˆ˜๊ฐ€ ์žˆ๋Š”์ง€๋งŒ ํ™•์ธํ•œ๋‹ค. ์ด ๋• ํƒ€์ดํ•‘(๋™์  ํƒ€์ดํ•‘์˜ ํ•œ ์ข…๋ฅ˜๋กœ, ๊ฐ์ฒด์˜ ๋ณ€์ˆ˜ ๋ฐ ๋ฉ”์†Œ๋“œ์˜ ์ง‘ํ•ฉ์ด ๊ฐ์ฒด์˜ ํƒ€์ž…์„ ๊ฒฐ์ •ํ•˜๋Š” ๊ฒƒ)์€ ์˜๋„์ ์ธ ๊ฒƒ์ด๋‹ค. ์˜๋„์ ์œผ๋กœ ๋ชจํ˜ธํ•˜๊ฒŒ ํ•œ ๊ฒƒ์œผ๋กœ, Promise์˜ ๊ตฌํ˜„์ฒด๊ฐ€ ์„œ๋กœ ์กฐ๊ธˆ ๋‹ค๋ฅธ 3rd Party ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ„์— ์ƒํ˜ธ๊ฐ„์˜ ์กฐํ•ฉ๋„ ์„œ๋กœ Promise์ด๋ผ๊ณ  ํ•ด์„ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

์ŠคํŽ™์„ ์ ์ ˆํ•˜๊ฒŒ ๋”ฐ๋ฅธ๋‹ค๋ฉด ์—ฌ๋Ÿฌ Promise ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์„ ์„œ๋กœ ์กฐํ•ฉํ•  ์ˆ˜ ์žˆ๋‹ค.

์—ฌ๊ธฐ์„œ ๋ฉ”์†Œ๋“œ ์ฒด์ด๋‹๊ณผ ํ•จ๊ป˜ Promise ๊ตฌํ˜„์ฒด๋Š” ์•„์ฃผ ์™„๋ฒฝํ•˜๋‹ค. ํ•˜์ง€๋งŒ ์—๋Ÿฌ ํ•ธ๋“ค๋ง ๋ถ€๋ถ„์€ ๋ฌด์‹œ๋˜์–ด ์žˆ๋Š” ๊ฒƒ์€ ์•Œ์•„ ๋‘์—ˆ์œผ๋ฉด ํ•œ๋‹ค.

Promise ๊ฑฐ๋ถ€ํ•˜๊ธฐ

Promise๊ฐ€ ์ฒ˜๋ฆฌ๋˜๋Š” ๋™์•ˆ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค๋ฉด ์‚ฌ์œ ์™€ ํ•จ๊ป˜ ๊ฑฐ๋ถ€(reject)ํ•ด์•ผ ํ•œ๋‹ค. ๊ฑฐ๋ถ€๋œ ๊ฒฝ์šฐ์— ํ˜ธ์ถœ์ž๋Š” ์–ด๋–ป๊ฒŒ ์•Œ ์ˆ˜ ์žˆ์„๊นŒ? ๊ทธ๊ฒƒ์€ then()์˜ ๋‘๋ฒˆ์งธ ์ฝœ๋ฐฑ ์ธ์ž์— ์˜ค๋ฅ˜ ๋ฐœ์ƒ์‹œ์— ์ฒ˜๋ฆฌ๋ฅผ ์ „๋‹ฌํ•˜์—ฌ ์˜ค๋ฅ˜ ์•Œ๋ฆผ์„ ์•Œ์•„์ฐจ๋ฆด ์ˆ˜ ์žˆ๋‹ค.

doSomething().then(function(value) {
  console.log('Success!', value);
}, function(error) {
  console.log('Uh oh', error);
});

์•ž์—์„œ ์–ธ๊ธ‰ํ•œ ๋ฐ”์™€ ๊ฐ™์ด, Promise ์ƒํƒœ๋Š” pending์—์„œ resolved, ๋˜๋Š” rejected ์ค‘ ํ•˜๋‚˜์˜ ์ƒํƒœ๋กœ ์ „ํ™˜ํ•œ๋‹ค. ๊ฒฐ์ฝ” ๋‘ ์ƒํƒœ๊ฐ€ ๋  ์ˆœ ์—†๋‹ค. ๋‹ค๋ฅธ๋ง๋กœ ํ•œ๋‹ค๋ฉด, ์œ„์˜ 2๊ฐœ์˜ ์ฝœ๋ฐฑ ์ค‘ ํ•˜๋‚˜๋งŒ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

Promise๊ฐ€ reject()์„ ์‹คํ–‰ํ•˜์—ฌ rejected๋ฅผ ํ™œ์„ฑํ™”ํ•  ์ˆ˜ ์žˆ์–ด, reject()๋ผ๋Š” ํ•จ์ˆ˜๋Š” resolve()์ฒ˜๋Ÿผ ์ค‘์š”ํ•œ ๊ธฐ๋Šฅ์„ ํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์•„๋ž˜์— doSomething()์—์„œ ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ๋ฅผ ์ถ”๊ฐ€ ๋˜์—ˆ๋‹ค.

function doSomething() {
  return new Promise(function(resolve, reject) {
    var result = somehowGetTheValue();
    if(result.error) {
      reject(result.error);
    } else {
      resolve(result.value);
    }
  });
}

Promise ๊ตฌํ˜„์ฒด ๋‚ด๋ถ€์—๋Š” ๊ฑฐ๋ถ€ ๊ธฐ๋Šฅ์ด ํ•„์š”ํ•˜๋‹ค. Promise๊ฐ€ reject๋˜๋ฉด ๊ทธ ์ดํ›„์˜ ๋ชจ๋“  Promise๋„ ๊ฑฐ๋ถ€๋  ํ•„์š”๊ฐ€ ์žˆ๋‹ค.

๊ทธ๋Ÿผ ๋‹ค์‹œ Promise ์ „์ฒด์— ๋Œ€ํ•œ ๊ตฌํ˜„์ฒด๋ฅผ ๋ณด์ž. ์ด๋ฒˆ์—๋Š” reject ๊ธฐ๋Šฅ์ด ์ถ”๊ฐ€ ๋˜์—ˆ๋‹ค.

function Promise(fn) {
  var state = 'pending';
  var value;
  var deferred = null;

  function resolve(newValue) {
    if(newValue && typeof newValue.then === 'function') {
      newValue.then(resolve, reject);
      return;
    }
    state = 'resolved';
    value = newValue;

    if(deferred) {
      handle(deferred);
    }
  }

  function reject(reason) {
    state = 'rejected';
    value = reason;

    if(deferred) {
      handle(deferred);
    }
  }

  function handle(handler) {
    if(state === 'pending') {
      deferred = handler;
      return;
    }

    var handlerCallback;

    if(state === 'resolved') {
      handlerCallback = handler.onResolved;
    } else {
      handlerCallback = handler.onRejected;
    }

    if(!handlerCallback) {
      if(state === 'resolved') {
        handler.resolve(value);
      } else {
        handler.reject(value);
      }

      return;
    }

    var ret = handlerCallback(value);
    handler.resolve(ret);
  }

  this.then = function(onResolved, onRejected) {
    return new Promise(function(resolve, reject) {
      handle({
        onResolved: onResolved,
        onRejected: onRejected,
        resolve: resolve,
        reject: reject
      });
    });
  };

  fn(resolve, reject);
}

์‹คํ–‰ ํ™”๋ฉด : Fiddle

reject()์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ ์™ธ์—๋„, handle() ์—์„œ๋„ reject๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค. handle()๋‚ด์—์„œ reject ํŒจ์Šค์™€ resolve ํŒจ์Šค๋Š” state ๊ฐ’์— ์˜ํ•ด ๊ฒฐ์ •๋œ๋‹ค. ์ด state ๊ฐ’์€ ๋‹ค์Œ Promise์— ์ „๋‹ฌ๋˜๊ณ  ๋‹ค์Œ Promise์—์„œ ๋ฐ›์€ state์˜ ๊ฐ’์„ ๋ฐ”ํƒ•์œผ๋กœ, reject()์™€ resolve()๋ฅผ ํ˜ธ์ถœํ•˜๋ฉฐ ์ž์‹ ์˜ state ๊ฐ’์œผ๋กœ ๋ฐ›์€ state ๊ฐ’์„ ์„ค์ •ํ•œ๋‹ค.

Promise๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ์˜ค๋ฅ˜ ์ฝœ๋ฐฑ์„ ์ƒ๋žตํ•˜๊ธฐ ์‰ฝ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์˜ค๋ฅ˜ ์ฝœ๋ฐฑ์„ ์ƒ๋žตํ•œ ๊ฒฝ์šฐ์—๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ๊ทธ๊ฒƒ์„ ์ฐพ์•„๊ฐˆ ์ˆ˜ ์—†๋‹ค. ์ ์–ด๋„ ์ฒด์ธ๋œ ๋งˆ์ง€๋ง‰ Promise์— ์—๋Ÿฌ ์ฝœ๋ฐฑ์„ ๊ฐ€์ง€๊ณ  ์žˆ์–ด์•ผ ํ•œ๋‹ค. ๋‚˜์ค‘์— ์ข€ ๋” ์ž์„ธํ•œ ๋‚ด์šฉ์„ ๋‹ค๋ฃฐ ๊ฒƒ์ด๋‹ค.

์˜ˆ๊ธฐ์น˜ ์•Š์€ ์˜ค๋ฅ˜๋„ reject์™€ ์—ฐ๊ฒฐ๋˜์–ด์•ผ ํ•œ๋‹ค.

์ง€๊ธˆ๊นŒ์ง€ ์—๋Ÿฌ ํ•ธ๋“ค๋ง์€ ์•Œ๋ ค์ง„ ์˜ค๋ฅ˜๋งŒ์„ ๋Œ€์ƒ์œผ๋กœํ•˜๊ณ  ์žˆ์—ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์˜ˆ์ƒ๋˜์ง€ ์•Š๋Š” ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•  ๊ฒฝ์šฐ์—๋Š” ๋ชจ๋“ ๊ฒŒ ํŒŒ๋ฉธ๋  ๊ฒƒ์ด๋‹ค.Promise์˜ ๊ตฌํ˜„์ฒด๋Š” ์˜ˆ๊ธฐ์น˜ ์•Š์€ ์˜ˆ์™ธ๋ฅผ ์บ์น˜ํ•˜๊ณ  ์ ์ ˆํ•˜๊ฒŒ rejectํ•˜๋Š” ๊ฒƒ์ด ํ•„์ˆ˜์ ์ด๋‹ค.

์ด๊ฒƒ์ด resolve() ๋ฉ”์†Œ๋“œ๋Š” try/cach ๋ธ”๋ก์œผ๋กœ ์—์›Œ์‹ธ์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.

function resolve(newValue) {
  try {
    // ... as before
  } catch(e) {
    reject(e);
  }
}

๋˜ํ•œ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์ค‘์š”ํ•œ ์ ์€ ํ˜ธ์ถœ์ž๊ฐ€ ์ง€์ •ํ•œ ์ฝœ๋ฐฑ์ด ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ์˜ˆ์™ธ๋ฅผ ๋˜์ง€์ง€ ์•Š์„ ์ˆ˜๋„ ์žˆ๋‹ค. ์ด ์ฝœ๋ฐฑ์€ handle()์—์„œ ํ˜ธ์ถœ๋˜๋Š”๋ฐ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ•ด๊ฒฐํ•œ๋‹ค.

function handle(deferred) {
  // ... as before

  var ret;
  try {
    ret = handlerCallback(value);
  } catch(e) {
    handler.reject(e);
    return;
  }

  handler.resolve(ret);
}

Promise๋Š” ์˜ค๋ฅ˜๋ฅผ ๋จน์–ด๋ฒ„๋ฆด ์ˆ˜ ์žˆ๋‹ค.

Promise ๋Œ€ํ•œ ์ดํ•ด๊ฐ€ ์ž˜ ๋ชปํ•˜๋ฉด ์—๋Ÿฌ๋ฅผ ์™„์ „ํžˆ ๋ฌต์‚ดํ•ด ๋ฒ„๋ฆฌ๋Š” ๊ตฌํ˜„์„ ํ•  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋‹ค. ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด ๊ฒช์„ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด๋‹ค.

๋‹ค์Œ ์˜ˆ๋ฅผ ์ƒ๊ฐํ•ด ๋ณด์ž.

function getSomeJson() {
  return new Promise(function(resolve, reject) {
    var badJson = "uh oh, this is not JSON at all!";
    resolve(badJson);
  });
}

getSomeJson().then(function(json) {
  var obj = JSON.parse(json);
  console.log(obj);
}, function(error) {
  console.log('uh oh', error);
});

์‹คํ–‰ ํ™”๋ฉด : Fiddle

๋ฌด์Šจ ์ผ์ด ์ผ์–ด๋‚ ๊นŒ? then()์˜ ์ฝœ๋ฐฑ ์ธ์ž๋Š” ์˜ฌ๋ฐ”๋ฅธ ํ˜•์‹์˜ JSON์„ ๋ฐ›์„ ๊ฒƒ์„ ์˜ˆ์ƒํ•œ๋‹ค. ์ฝœ๋ฐฑ์—์„œ ๋ฐ›์€ ๊ฐ’์„ ํ™•์ธํ•˜์ง€ ์•Š๊ณ  JSON ํŒŒ์‹ฑํ•˜๋ฉด ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๊ฒŒ ๋œ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์šฐ๋ฆฌ๊ฐ€ ์˜ค๋ฅ˜๊ฐ€์žˆ์„ ๊ฒฝ์šฐ์— ๋Œ€๋น„ํ•˜์—ฌ then()์˜ ๋‘๋ฒˆ์งธ ํŒŒ๋ผ๋ฏธํ„ฐ์— ์˜ค๋ฅ˜ ์ฝœ๋ฐฑ์„ ์ง€์ •ํ•œ๋‹ค. ์ด๋ ‡๊ฒŒ ๊ตฌํ˜„ํ•˜๋ฉด ์˜๋„๋Œ€๋กœ ์—๋Ÿฌ ์ฝœ๋ฐฑ์ด ํ˜ธ์ถœ๋˜๋Š” ๊ฒƒ์ผ๊นŒ?

์•„๋‹ˆ๋‹ค. ์˜ค๋ฅ˜ ์ฝœ๋ฐฑ์€ ํ˜ธ์ถœ๋˜์ง€ ์•Š๋Š”๋‹ค. ์œ„์˜ fiddle ์˜ˆ์ œ๋ฅผ ์‹คํ–‰ํ•ด ๋ณด๋ฉด ์•„๋ฌด๊ฒƒ๋„ ์ถœ๋ ฅํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค. ๋“ฑ๊ณจ์ด ์„œ๋Š˜ํ•ด์ง„๋‹ค.

์™œ ๊ทธ๋ ‡๊ฒŒ ๋ ๊นŒ? ์ด๊ฒƒ์€ ์˜ˆ๊ธฐ์น˜ ์•Š์€ ์˜ค๋ฅ˜(JSON ํŒŒ์‹ฑ์— ์‹คํŒจํ•œ ์˜ˆ์™ธ)๋Š” handle()๋‚ด์—์„œ ์บ์น˜๋˜์ง€๋งŒ, JSON ํŒŒ์‹ฑ ์ฒ˜๋ฆฌ๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ์—๋Š” ๋Œ€์ƒ Promise๋Š” ์ด๋ฏธ resolved ์ƒํƒœ์ด๊ธฐ ๋•Œ๋ฌธ์— reject๊ฐ€ ํ˜ธ์ถœ๋˜์ง€ ์•Š๋Š”๋‹ค. ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•œ ๊ฒฝ์šฐ์—๋Š” ๋‹ค์Œ Promise๊ฐ€ reject๋œ๋‹ค.

ํ•ญ์ƒ ๊ธฐ์–ตํ•˜๋ผ. then()์ฝœ๋ฐฑ ์•ˆ์—, Promise๋Š” ์ด๋ฏธ resolved ์ƒํƒœํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์ฝœ๋ฐฑ์˜ ๊ฒฐ๊ณผ๊ฐ€ ๋ฌด์—‡์ด๋“  Promise์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๋Š”๋‹ค.

๋งŒ์•ฝ ์œ„์˜ ์˜ค๋ฅ˜๋ฅผ ์ผ€์น˜ํ•˜๋ ค๋ฉด ์˜ค๋ฅ˜ ์ฝœ๋ฐฑ์„ ๋‹ค์Œ then()์—์„œ ์ง€์ •ํ•ด์•ผ ํ•œ๋‹ค.

getSomeJson().then(function(json) {
  var obj = JSON.parse(json);
  console.log(obj);
}).then(null, function(error) {
  console.log("an error occured: ", error);
});

์ด์ œ ์˜ค๋ฅ˜ ๋กœ๊ทธ๋ฅผ ์ œ๋Œ€๋กœ ๊ธฐ๋ก ํ•  ์ˆ˜ ์žˆ๋‹ค.

๋‚ด ๊ฒฝํ—˜์ƒ,์ด ์ ์ด Promise์˜ ๊ฐ€์žฅ ํฐ ํ•จ์ •์ด๋‹ค. ๋” ๋‚˜์€ ํ•ด๊ฒฐ์ฑ…์„ ์œ„ํ•ด์„œ๋Š” ๋‹ค์Œ ์„น์…˜์„ ์ฝ์–ด๋ผ.

done()์„ ๊ตฌ์ œ์šฉ์œผ๋กœ ์‚ฌ์šฉํ•˜์ž

(์ „๋ถ€๋Š” ์•„๋‹ˆ์ง€๋งŒ) ๋Œ€๋ถ€๋ถ„์˜ Promise ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์€ done() ๋ฉ”์†Œ๋“œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค. ์ด๊ฒƒ์€ then()๊ณผ ๋งค์šฐ ๋น„์Šทํ•˜์ง€๋งŒ, done()์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์œผ๋กœ ์œ„์—์„œ ๋งํ•œ๊ฒƒ์ฒ˜๋Ÿผ then()์˜ ํ•จ์ •์„ ํ”ผํ•  ์ˆ˜ ์žˆ๋‹ค. done()์€ then()์ด ํ˜ธ์ถœ๋˜๋Š” ๊ณณ์—์„œ๋Š” ์–ธ์ œ๋ผ๋„ ํ˜ธ์ถœ ํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ฐ€์žฅ ํฐ ์ฐจ์ด๋Š” done()์€ Promise๋ฅผ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ๋˜ํ•œ done()๋‚ด์—์„œ ๋ฐœ์ƒํ•œ ์–ด๋– ํ•œ ์˜ˆ์™ธ๋„ Promise ๊ตฌํ˜„์ฒด์—์„œ ์บ์น˜๋˜์ง€ ์•Š๋Š”๋‹ค. ๋‹ค๋ฅธํ•œํŽธ์œผ๋กœ, done()์€ Promise ์ฒด์ธ์ด ๋ชจ๋‘ resolved๋˜์—ˆ์„ ๋•Œ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์ด๋‹ค. getSomeJson() ์˜ˆ์ œ๋Š” done()์„ ์‚ฌ์šฉํ•ด ์ข€ ๋” ์™„์ „ํ•œ ๊ตฌํ˜„์ฒด๊ฐ€ ๋  ์ˆ˜ ์žˆ๋‹ค.

getSomeJson().done(function(json) {
  // when this throws, it won't be swallowed
  var obj = JSON.parse(json);
  console.log(obj);
});

done()์— ์˜ค๋ฅ˜ ์ฝœ๋ฐฑ์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, then()๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ done(callback, errback)๋ผ๋Š” ์ƒํƒœ๋กœ ์ง€์ •ํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ์˜ค๋ฅ˜ ์ฝœ๋ฐฑ(errback)์ด Promise ์ž‘์—…์ด ์™„์ „ํžˆ ์ข…๋ฃŒํ•˜๊ณ  ํ˜ธ์ถœ๋˜๋ฏ€๋กœ Promise๋ฅผ ์ด์šฉํ•œ ์ผ๋ จ์˜ ์ฒ˜๋ฆฌ์—์„œ ๋ฐœ์ƒํ•œ ์–ด๋– ํ•œ ์˜ค๋ฅ˜๋„ ์บ์น˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

done()์€ (์ ์–ด๋„ ๋‹น๋ถ„๊ฐ„์€) Promise/A+์˜ ์ŠคํŽ™์ด ์•„๋‹ˆ๋ฏ€๋กœ, Promise ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ์˜ํ•ด ๊ตฌํ˜„๋˜์ง€ ์•Š์„ ์ˆ˜๋„ ์žˆ๋‹ค.

Promise์˜ ์ข…๋ฃŒ๋Š” ๋น„๋™๊ธฐ๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

์ด ์•„ํ‹ฐํด์˜ ์ดˆ๊ธฐ์— setTimeout์„ ์‚ฌ์šฉํ•ด ์•ฝ๊ฐ„์˜ ์†์ž„์ˆ˜๋ฅผ ์ผ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ํ•ดํ‚น ์œ„ํ˜‘์œผ๋กœ ์ด๋ฅผ ์ˆ˜์ •ํ•˜์—ฌ setTimeout์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•˜๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์‹ค์ œ๋กœ Promise/A+์˜ ์ŠคํŽ™์€ Promise ์ข…๋ฃŒ๋Š” ๋น„๋™๊ธฐ์ ์œผ๋กœ ์ด๋ฃจ์–ด์ง„๋‹ค. ์ด ์ŠคํŽ™์˜ ์š”๊ตฌ์‚ฌํ•ญ์„ ์ถฉ์กฑํ•˜๊ธฐ ์œ„ํ•ด handle() ํ•จ์ˆ˜ ๊ตฌํ˜„์˜ ๋Œ€๋ถ€๋ถ„์„ setTimeout ํ˜ธ์ถœ๋กœ ๊ฐ์Œ€ ํ•„์š”๊ฐ€ ์žˆ๋‹ค.

function handle(handler) {
  if(state === 'pending') {
    deferred = handler;
    return;
  }
  setTimeout(function() {
    // ... as before
  }, 1);
}

Promise/A+ ํ•„์š”ํ•œ ๊ตฌํ˜„์€ ์ด์ƒ์ด ์ „๋ถ€๋‹ค. ์‚ฌ์‹ค, ๋งŽ์€ Promise ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—์„œ ๋น„๋™๊ธฐ๋ฅผ ์ง€์›ํ•˜๊ธฐ ์œ„ํ•ด setTimeout์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค. ๋งŒ์•ฝ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ NodeJS์—์„œ ์ž‘๋™ํ•˜๋Š” ๊ฒฝ์šฐ๋ผ๋ฉด process.nextTick์„ ์‚ฌ์šฉํ•  ๊ฒƒ์ด๊ณ , ๋งŒ์•ฝ ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ž‘๋™ํ•˜๋Š” ๊ฒฝ์šฐ๋ฉด setImmediate๋‚˜ setImmediate shim(์ง€๊ธˆ IE์—์„œ๋งŒ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค)์™€ Kris Kowal์˜ asap(Kris Kowal์€ Q๋ผ๋Š” ์ธ๊ธฐ์žˆ๋Š” Promise ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ) ๊ฐ™์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ• ์ง€๋„ ๋ชจ๋ฅธ๋‹ค.

์™œ ์ด๋Ÿฌํ•œ ๋น„๋™๊ธฐ ์š”๊ตฌ ์‚ฌํ•ญ์ด ์ŠคํŽ™์— ์žˆ๋Š”๊ฐ€?

๋น„๋™๊ธฐ๋ฅผ ์ง€์›ํ•จ์œผ๋กœ์จ ์ผ๊ด€์„ฑ๊ณผ ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ๋Š” ํ๋ฆ„์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ๋‹ค. ๋‹ค์Œ์˜ ์–ต์ง€๋กœ ๊พธ๋ฏผ ์˜ˆ๋ฅผ ์‚ดํŽด ๋ณด์ž.

var promise = doAnOperation();
invokeSomething();
promise.then(wrapItAllUp);
invokeSomethingElse();

์ด ๊ตฌํ˜„์—์„œ ์ฒ˜๋ฆฌ ์ˆœ์„œ๋Š” ์–ด๋–ป๊ฒŒ ๋ ๊นŒ? ์ด๋ฆ„์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์ถ”์ธกํ•ด ๋ณด๋ฉด, invokeSomething() -> invokeSomethingElse() -> wrapItAllUp() ์ˆœ์œผ๋กœ ํ˜ธ์ถœ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ์„ค๊ณ„๋˜์–ด ์žˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด๋Ÿฐ ์‹คํ–‰ ์ˆœ์„œ๋Š” Promise์˜ resolve ์ฒ˜๋ฆฌ๊ฐ€ ๋™๊ธฐ์ ์ธ์ง€ ๋น„๋™๊ธฐ์ ์œผ๋กœ ์ˆ˜ํ–‰๋˜๋Š”์ง€์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์ง„๋‹ค. ๋งŒ์•ฝ, doAnOperation() ํ•จ์ˆ˜๊ฐ€ ๋น„๋™๊ธฐ์ ์œผ๋กœ ์ฒ˜๋ฆฌ๋œ๋‹ค๋ฉด ์œ„์˜ ์˜ˆ์ƒ๋Œ€๋กœ ์‹คํ–‰ ์ˆœ์„œ๊ฐ€ ๋  ๊ฒƒ์ด๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ doAnOperation()์ด ๋™๊ธฐ์ ์œผ๋กœ ์ฒ˜๋ฆฌ๋  ๊ฒฝ์šฐ invokeSomething() -> wrapItAllUp() -> invokeSomethingElse() ์ˆœ์œผ๋กœ ๋˜์–ด ๊ฐ€์ •ํ•œ ๊ฒƒ๊ณผ ๋‹ค๋ฅธ ๊ฒฐ๊ณผ๊ฐ€๋˜์–ด ๋ฒ„๋ฆฐ๋‹ค. ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด Promise๋Š” ํ•ญ์ƒ ๋น„๋™๊ธฐ์ ์œผ๋กœ resolved ๋˜์–ด์•ผ ํ•œ๋‹ค. ์‹ฌ์ง€์–ด ๋น„๋™๊ธฐ๊ฐ€ ์•„๋‹๋•Œ๋„. Promise๊ฐ€ ๋น„๋™๊ธฐ์ ์œผ๋กœ resolved ๋จ์œผ๋กœ์จ(ํ•ฉ๋ฆฌ์ ์ธ ์ฝ”๋“œ์— ๋น„์œ ) Promise ์ด์šฉ์ž๋Š” Promise๊ฐ€ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ์— ๋Œ€์‘ํ•˜๊ณ  ์žˆ๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ์ƒ๊ฐํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค.

Promise๋Š” resolved๋˜๊ธฐ ์œ„ํ•ด์„œ ํ•œ๋ฒˆ ์ด์ƒ์˜ ์ด๋ฒคํŠธ ๋ฃจํ”„(์ž‘์—…์˜ ์ฃผ ์Šค๋ ˆ๋“œ์—์„œ ๋ฃจํ”„)๊ฐ€ ํ•„์š”ํ•˜๋‹ค. ์ด๊ฒƒ์€ ํ‘œ์ค€ ์ฝœ๋ฐฑ ์ ‘๊ทผ ๋ฐฉ์‹์˜ ํ•„์ˆ˜๋Š” ์•„๋‹ˆ๋‹ค.

then/promise ์ด์•ผ๊ธฐ๋ฅผ ๋๋‚ด๊ธฐ ์ „์—

์„ธ์ƒ์—๋Š” Promise ์ŠคํŽ™์„ ๋ชจ๋‘ ์ถฉ์กฑ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ๋งŽ์ด ์žˆ๋‹ค. ๊ทธ ์ค‘์—์„œ๋„ then ํŒ€์˜ promise ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ์ƒ๋‹นํžˆ ์‹ฌํ”Œํ•˜๋‹ค. ๊ทธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ๊ฐ„๋‹จํ•œ ๊ตฌํ˜„ ์ŠคํŽ™์„ ์ถฉ์กฑํ•˜๊ณ  ์žˆ๊ณ  ์ŠคํŽ™ ์ด์™ธ์˜ ๊ฒƒ์€ ๊ตฌํ˜„ํ•˜์ง€ ์•Š์•˜๋‹ค. ๋งŒ์•ฝ ๊ทธ ๊ตฌํ˜„์„ ๋ณผ ๊ธฐํšŒ๊ฐ€ ์žˆ์œผ๋ฉด, ๊ทธ ๊ตฌํ˜„์ด ์—ฌ๊ธฐ์™€ ๋งค์šฐ ๋น„์Šทํ•˜๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค. thenํŒ€์˜ promise ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ์ด ์•„ํ‹ฐํด์„ ์“ฐ๊ธฐ ์œ„ํ•œ ๊ธฐ๋ฐ˜์ด ๋˜์—ˆ๊ณ , ์šฐ๋ฆฌ๋Š” ๊ฑฐ์˜ ๋น„์Šทํ•œ ๊ตฌํ˜„์ฒด๋ฅผ ์—ฌ๊ธฐ ์•„ํ‹ฐํด์— ๊ตฌ์ถ•ํ–ˆ๋‹ค. ๊ฐœ๋ฐœ์ž์ธ Nathan Zadoks์™€ Forbes Lindsay์˜ ์œ„๋Œ€ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋•๋ถ„์— JavaScript Promise๋ฅผ ์ž‘๋™์‹œํ‚ฌ ์ˆ˜ ์žˆ์—ˆ๋‹ค. ๋˜ํ•œ Forbes Lindsay๋Š” promisejs.org ์‚ฌ์ดํŠธ๋ฅผ ์‹œ์ž‘ํ–ˆ๋‹ค๊ณ  ์–ธ๊ธ‰ํ–ˆ๋‹ค.

์ด ์•„ํ‹ฐํด์—์„œ ๊ตฌํ˜„ํ•œ ๋‚ด์šฉ๊ณผ ์‹ค์ œ ๊ตฌํ˜„์—๋Š” ๋ช‡ ๊ฐ€์ง€ ์ฐจ์ด์ ์ด ์žˆ๋‹ค. ๊ทธ๊ฒƒ์€ Promise/A+๋Š” ์—ฌ๊ธฐ์„œ ๋‹ค๋ฃจ์ง€ ์•Š๋Š” ๋‹ค๋ฅธ ์ž์„ธํ•œ ์ŠคํŽ™๋“ค์ด ์ •์˜๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๊ผญ Promise/A+ ์ŠคํŽ™ ์ฝ์–ด ๋ณด๊ธธ ๊ถŒํ•œ๋‹ค. ๋ช…์„ธ์„œ๋Š” ๋น„๊ต์  ์งง๊ณ  ์ฝ๊ธฐ ์‰ฝ๋‹ค.

๊ฒฐ๋ก 

๋๊นŒ์ง€ ์ฝ์–ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•˜๋‹ค. ์ง€๊ธˆ๊นŒ์ง€ Promise์˜ ํ•ต์‹ฌ ๋ถ€๋ถ„์„ ๋‹ค๋ค„์™”๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋งŽ์€ Promise ๊ตฌํ˜„ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” all() , race() , denodeify() ๋“ฑ ๊ทธ ๋ฐ–์—๋„ ๋‹ค์–‘ํ•œ ๊ธฐ๋Šฅ๋“ค์ด ์ œ๊ณต๋˜๊ณ  ์žˆ๋‹ค. Promise์˜ ๊ฐ€๋Šฅ์„ฑ์„ ์•Œ๊ธฐ์œ„ํ•ด์„œ๋Š” API docs for Bluebird๋ฅผ ์ฝ๋Š” ๊ฒƒ์ด ์ข‹๋‹ค. ๋‚˜๋Š” Promise๊ฐ€ ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€, ๊ทธ๋ฆฌ๊ณ  ๋ฌด์—‡์„ ํ•ด๊ฒฐํ•˜๋ ค๊ณ  ํ•˜๊ณ  ์žˆ๋Š”์ง€๋ฅผ ์ดํ•ดํ•˜๊ณ ๋ถ€ํ„ฐ๋Š”, Promise ์ •๋ง ์ข‹์•„ํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค. Promise๋Š” ๋‚ด ํ”„๋กœ์ ํŠธ ์ฝ”๋“œ๋ฅผ ๋งค์šฐ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ๊ทธ๋ฆฌ๊ณ  ์šฐ์•„ํ•˜๊ฒŒ ํ•ด์ค€๋‹ค. ๋”์šฑ ๋”ํ•˜๊ณ  ์‹ถ์€ ๋ง์€ ์ด ๋ฌธ์„œ๋Š” ์„œ๋ฌธ์— ์ง€๋‚˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.