javascript promises for dummies - Lee-hyuna/33-js-concepts-kr GitHub Wiki

Javascript ํ”„๋ผ๋ฏธ์Šค

์›๋ฌธ: JavaScript Promises for Dummies

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ”„๋ผ๋ฏธ์Šค๋Š” ์–ด๋ ต์ง€ ์•Š๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์€ ์ฒ˜์Œ์— ์ดํ•ดํ•˜๊ธฐ๊ฐ€ ์กฐ๊ธˆ ์–ด๋ ต๋‹ค๋Š” ๊ฒƒ์„ ์•ˆ๋‹ค. ๋”ฐ๋ผ์„œ ํ”„๋ผ๋งˆ์Šค๋ฅผ ์ดํ•ดํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋” ์‰ฌ์šด ๋ฐฉ๋ฒ•์œผ๋กœ ์ ์œผ๋ ค ํ•œ๋‹ค.

ํ”„๋ผ๋ฏธ์Šค ์ดํ•ดํ•˜๊ธฐ

ํ”„๋ผ๋ฏธ์Šค๋Š” ๊ฐ„๋‹จํžˆ ๋งํ•ด์„œ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

"๋‹น์‹ ์ด ์–ด๋ฆฐ์•„์ด๋ผ๊ณ  ์ƒ์ƒํ•ด๋ณด์ž. ์—„๋งˆ๊ฐ€ ๋‹ค์Œ ์ฃผ์— ์ƒˆ๋กœ์šด ํœด๋Œ€์ „ํ™”๋ฅผ ์‚ฌ์ฃผ๊ฒ ๋‹ค๊ณ  ์•ฝ์†(promise) ํ–ˆ๋‹ค"

๋‹ค์Œ ์ฃผ๊ฐ€ ๋˜๊ธฐ์ „๊นŒ์ง€ ํœด๋Œ€์ „ํ™”๋ฅผ ๋ฐ›์„ ์ˆ˜ ์žˆ์„์ง€ ์•Œ์ˆ˜๊ฐ€ ์—†๋‹ค. ์—„๋งˆ๊ฐ€ ์ •๋ง๋กœ ์ƒˆ ํœด๋Œ€์ „ํ™”๋ฅผ ์‚ฌ์ค„ ์ˆ˜๋„ ์žˆ๊ณ , ์‚ฌ์ฃผ์ง€ ์•Š๊ณ  ๋ณด๋ฅ˜ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

์ด๊ฒŒ ๋ฐ”๋กœ ํ”„๋ผ๋ฏธ์Šค์ด๋‹ค. ํ”„๋ผ๋ฏธ์Šค๋Š” 3๊ฐ€์ง€์˜ ์ƒํƒœ ๊ฐ’์„ ๊ฐ€์ง„๋‹ค.

  1. Pending: ์ƒˆ๋กœ์šด ํœด๋Œ€์ „ํ™”๋ฅผ ๋ฐ›์„์ง€๋„ ๋ชจ๋ฅด๋Š” ์ƒํƒœ
  2. Fulfilled: ์—„๋งˆ๊ฐ€ ์ƒˆ๋กœ์šด ํœด๋Œ€์ „ํ™”๋ฅผ ์‚ฌ์ค€ ์ƒํƒœ
  3. Rejected: ์—„๋งˆ๊ฐ€ ๊ตฌ๋งค๋ฅผ ๋ณด๋ฅ˜ํ•œ ์ƒํƒœ

ํ”„๋ผ๋ฏธ์Šค ๋งŒ๋“ค๊ธฐ

์ž, ์ด์ œ ์ด๊ฒƒ๋“ค์„ ์‹ค์ œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ๊ตฌํ˜„ํ•ด ๋ณด์ž.

/_ ES5 _/
var isMomHappy = false;

// Promise
var willIGetNewPhone = new Promise(
    function (resolve, reject) {
        if (isMomHappy) {
            var phone = {
                brand: 'Samsung',
                color: 'black'
            };
            resolve(phone); // fulfilled
        } else {
            var reason = new Error('mom is not happy');
            reject(reason); // reject
        }

    }
);

์ด ์ฝ”๋“œ๋Š” ์ด ์ž์ฒด๋กœ ๊ฝค ํ‘œํ˜„๋ ฅ์ด ์žˆ๋‹ค.

// ํ”„๋ผ๋ฏธ์Šค ๊ตฌ๋ฌธ์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.
new Promise(function (resolve, reject) { ... } );

ํ”„๋ผ๋ฏธ์Šค ์‚ฌ์šฉํ•˜๊ธฐ

์ด์ œ ํ”„๋ผ๋ฏธ์Šค๋ฅผ ์–ป์—ˆ์œผ๋‹ˆ, ์‚ฌ์šฉํ•ด ๋ณด์ž. ์œ„์˜ ์˜ˆ์ œ์™€ ์ด์–ด์ง„๋‹ค.

/_ ES5 _/
...

// call our promise
var askMom = function () {
    willIGetNewPhone
        .then(function (fulfilled) {
            // ์ƒˆ๋กœ์šด ํœด๋Œ€์ „ํ™”๊ฐ€ ์ƒ๊ฒผ๋‹ค!
            console.log(fulfilled);
         // output: { brand: 'Samsung', color: 'black' }
        })
        .catch(function (error) {
            // ์ด๋Ÿฐ, ์—„๋งˆ๊ฐ€ ์‚ฌ์ฃผ์ง€ ์•Š์•˜์–ด..
            console.log(error.message);
         // output: 'mom is not happy'
        });
};

askMom();

์˜ˆ์ œ๋ฅผ ๋Œ๋ ค๋ณด๊ณ  ๊ฒฐ๊ณผ๋ฅผ ํ™•์ธํ•ด ๋ณด์ž!

Demo: https://jsbin.com/nifocu/1/edit?js,console

Result

ํ”„๋ผ๋ฏธ์Šค ์ฒด์ด๋‹

ํ”„๋ผ๋ฏธ์Šค๋Š” chainableํ•˜๋‹ค. ์ด์–ด์„œ ํ˜ธ์ถœ์ด ๊ฐ€๋Šฅํ•˜๋‹ค๋Š” ์ด์•ผ๊ธฐ์ด๋‹ค.

๋‹ค์‹œ ์ƒ์ƒํ•ด๋ณด์ž. ๋‹น์‹ ์€ ์–ด๋ฆฐ์•„์ด์ด๊ณ , ์นœ๊ตฌ์—๊ฒŒ ์—„๋งˆ๊ฐ€ ์ƒˆ๋กœ์šด ํœด๋Œ€์ „ํ™”๋ฅผ ์‚ฌ์ฃผ๋ฉด ๋ณด์—ฌ์ฃผ๊ฒ ๋‹ค๊ณ  ์•ฝ์†ํ•œ๋‹ค.

์ด์ œ ๋˜๋‹ค๋ฅธ ํ”„๋ผ๋ฏธ์Šค๊ฐ€ ์ƒ๊ฒผ๋‹ค. ์ž‘์„ฑํ•ด๋ณด์ž.

...

// 2nd promise
var showOff = function (phone) {
    return new Promise(
        function (resolve, reject) {
            var message = 'Hey friend, I have a new ' +
                phone.color + ' ' + phone.brand + ' phone';

            resolve(message);
        }
    );
};

์ถ•์•ฝํ•˜์ž๋ฉด :

// ์œ„์˜ ์˜ˆ์ œ๋ฅผ ์ถ•์•ฝํ•ด๋ณด์ž
...

// 2nd promise
var showOff = function (phone) {
 var message = 'Hey friend, I have a new ' +
                phone.color + ' ' + phone.brand + ' phone';

    return Promise.resolve(message);
};

ํ”„๋ผ๋ฏธ์Šค๋ฅผ ์ฒด์ด๋‹ ํ•ด๋ณด์ž. willIGetNewPhone ํ”„๋ผ๋ฏธ์Šค ํ›„์— showOff ํ”„๋ผ๋ฏธ์Šค๋ฅผ ์ดํ–‰ํ•  ํ•  ๊ฒƒ์ด๋‹ค.

...

// ์šฐ๋ฆฌ์˜ ํ”„๋ผ๋ฏธ์Šค๋ฅผ ํ˜ธ์ถœํ•ด๋ณด์ž.
var askMom = function () {
    willIGetNewPhone
    .then(showOff) // chain it here
    .then(function (fulfilled) {
            console.log(fulfilled);
         // output: 'Hey friend, I have a new black Samsung phone.'
        })
        .catch(function (error) {
            // ์ด๋Ÿฐ, ์—„๋งˆ๊ฐ€ ์‚ฌ์ฃผ์ง€ ์•Š์•˜์–ด..
            console.log(error.message);
         // output: 'mom is not happy'
        });
};

์–ผ๋งˆ๋‚˜ ํ”„๋ผ๋ฏธ์Šค๋ฅผ ์ฒด์ด๋‹ํ•˜๋Š”๊ฒŒ ์‰ฌ์šด์ง€ ์•Œ๊ฒ ๋Š”๊ฐ€?

ํ”„๋ผ๋ฏธ์Šค๋Š” ๋น„๋™๊ธฐ

ํ”„๋ผ๋ฏธ์Šค๋Š” ๋น„๋™๊ธฐ์ด๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ํ”„๋ผ๋ฏธ์Šค๋ฅผ ํ˜ธ์ถœ ํ•˜๊ธฐ ์ „๊ณผ ํ›„์— ๋กœ๊ทธ ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด์ž.

// ํ”„๋ผ๋ฏธ์Šค๋ฅผ ํ˜ธ์ถœ
var askMom = function () {
    console.log('์—„๋งˆ์—๊ฒŒ ๋ฌป๊ธฐ ์ „'); // log before
    willIGetNewPhone
        .then(showOff)
        .then(function (fulfilled) {
            console.log(fulfilled);
        })
        .catch(function (error) {
            console.log(error.message);
        });
    console.log('์—„๋งˆ์—๊ฒŒ ๋ฌผ์€ ํ›„'); // log after
}

์˜ˆ์ƒ ์ถœ๋ ฅ ์ˆœ์„œ๋Š” ์–ด๋– ํ•œ๊ฐ€? ์•„๋งˆ๋„ ๋‹ค์Œ์„ ์˜ˆ์ƒํ•  ๊ฒƒ์ด๋‹ค.

1. before asking Mom
2. Hey friend, I have a new black Samsung phone.
3. after asking mom

๊ทธ๋Ÿฌ๋‚˜ ์‹ค์ œ ์ถœ๋ ฅ ์ˆœ์„œ๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

1. before asking Mom
2. after asking mom
3. Hey friend, I have a new black Samsung phone.

Output

์™œ ๊ทธ๋Ÿด๊นŒ? ์„ธ์›”์€ ์‚ฌ๋žŒ์„ ๊ธฐ๋‹ค๋ ค์ฃผ์ง€ ์•Š๋Š”๋‹ค.

์–ด๋ฆฐ์•„์ด๋Š” ์—„๋งˆ๊ฐ€ ์•ฝ์†(์ƒˆ๋กœ์šด ํœด๋Œ€์ „ํ™”)์„ ์ง€ํ‚ฌ๋•Œ ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ๋ฉด์„œ ๊ฐ€๋งŒํžˆ ์žˆ์ง€ ์•Š๋Š”๋‹ค. ๊ทธ๋ ‡์ง€? ์ด ๊ฒƒ์„ ๋น„๋™๊ธฐ๋ผ๊ณ  ๋ถ€๋ฅด๋Š” ๊ฒƒ์ด๋‹ค. ํ”„๋ผ๋ฏธ์Šค๊ฐ€ ์ง„ํ–‰ ๋ ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ ค์•ผํ•˜๋Š” ๊ฒƒ์€ then์— ๋„ฃ์–ด์•ผ ํ•œ๋‹ค.

ES5, ES6/2015, ES7/Next ์˜ ํ”„๋ผ๋ฏธ์Šค

ES5 - ๋‹ค์ˆ˜์˜ ๋ธŒ๋ผ์šฐ์ €

Bluebird ํ”„๋ผ๋ฏธ์Šค ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ include ํ•˜๋ฉด, ์˜ˆ์ œ๋“ค์€ ES5 ํ™˜๊ฒฝ์—์„œ ๋™์ž‘ํ•  ๊ฒƒ์ด๋‹ค. ES5๋Š” ํ”„๋ผ๋ฏธ์Šค๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š๋Š”๋‹ค. ๋˜๋‹ค๋ฅธ ์œ ๋ช…ํ•œ ํ”„๋ผ๋ฏธ์Šค ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” Q์ด๋‹ค.

ES6 / ES2015 - ๋ชจ๋˜ ๋ธŒ๋ผ์šฐ์ €, NodeJs v6

์˜ˆ์ œ๋“ค์€ ์ž˜ ๋™์ž‘ํ•  ๊ฒƒ์ด๋‹ค. ES6๋Š” ์ž์ฒด์ ์œผ๋กœ ํ”„๋ผ๋ฏธ์Šค๋ฅผ ์ง€์›ํ•œ๋‹ค. ์ถ”๊ฐ€๋กœ ES6์—์„  const์™€ let์„ ์ด์šฉํ•˜์—ฌ ํ•จ์ˆ˜๋ฅผ ํ™”์‚ดํ‘œ๋กœ ์ด์šฉํ•˜์—ฌ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

์—ฌ๊ธฐ ES6 ์˜ˆ์ œ ์ฝ”๋“œ๊ฐ€ ์žˆ๋‹ค.

/_ ES6 _/
const isMomHappy = true;

// Promise
const willIGetNewPhone = new Promise(
    (resolve, reject) => { // fat arrow
        if (isMomHappy) {
            const phone = {
                brand: 'Samsung',
                color: 'black'
            };
            resolve(phone);
        } else {
            const reason = new Error('mom is not happy');
            reject(reason);
        }

    }
);

const showOff = function (phone) {
    const message = 'Hey friend, I have a new ' +
                phone.color + ' ' + phone.brand + ' phone';
    return Promise.resolve(message);
};

// call our promise
const askMom = function () {
    willIGetNewPhone
        .then(showOff)
        .then(fulfilled => console.log(fulfilled)) // fat arrow
        .catch(error => console.log(error.message)); // fat arrow
};

askMom();

๋ชจ๋“  var ๋“ค์€ const๋กœ ๋Œ€์ฒด๋˜์—ˆ๋‹ค. ๋ชจ๋“  function(resolve, reject)๋Š” ๋‹จ์ˆœํ•˜๊ฒŒ (resolve, reject) =>๋กœ ๋ณ€ํ–ˆ๋‹ค.

ES7 - Async Await: ์ฝ”๋“œ๊ฐ€ ๋” ์˜ˆ์˜๊ฒŒ ๋ณด์ด๋„๋ก ๋งŒ๋“ค๊ธฐ

ES7๋Š” async๋ฐ await ๊ตฌ๋ฌธ์„ ์†Œ๊ฐœํ–ˆ๋‹ค. ์ด ๊ฒƒ๋“ค์€ .thenํ•˜๊ณ  .catch๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ๋น„๋™๊ธฐ ๊ตฌ๋ฌธ์„ ์ด์˜๊ฒŒ ๋ณด์ด๊ฒŒ ํ•˜๋ฉฐ ์ดํ•ดํ•˜๊ธฐ ์‰ฝ๊ฒŒ ๋งŒ๋“ ๋‹ค.

์šฐ๋ฆฌ์˜ ์˜ˆ์ œ๋ฅผ ES7 ๊ตฌ๋ฌธ์œผ๋กœ ๋งŒ๋“ค์–ด ๋ณด์ž.

/_ ES7 _/
const isMomHappy = true;

// Promise
const willIGetNewPhone = new Promise(
    (resolve, reject) => {
        if (isMomHappy) {
            const phone = {
                brand: 'Samsung',
                color: 'black'
            };
            resolve(phone);
        } else {
            const reason = new Error('mom is not happy');
            reject(reason);
        }

    }
);

// 2nd promise
async function showOff(phone) {
    return new Promise(
        (resolve, reject) => {
            var message = 'Hey friend, I have a new ' +
                phone.color + ' ' + phone.brand + ' phone';

            resolve(message);
        }
    );
};

// call our promise
async function askMom() {
    try {
        console.log('before asking Mom');

        let phone = await willIGetNewPhone;
        let message = await showOff(phone);

        console.log(message);
        console.log('after asking mom');
    }
    catch (error) {
        console.log(error.message);
    }
}

(async () => {
    await askMom();
})();

์™œ ํ”„๋ผ๋ฏธ์Šค์ด๋ฉฐ ์–ธ์ œ ์จ์•ผํ• ๊นŒ?

์™œ ํ”„๋ผ๋ฏธ์Šค๊ฐ€ ํ•„์š”ํ• ๊นŒ? ํ”„๋ผ๋ฏธ์Šค ์ด์ „์—๋Š” ์ฝ”๋“œ๋ฅผ ์–ด๋–ป๊ฒŒ ์ž‘์„ฑํ–ˆ์„๊นŒ? ์ด ์งˆ๋ฌธ์— ๋Œ€๋‹ตํ•˜๊ธฐ ์ „์— ๊ธฐ๋ณธ์œผ๋กœ ๋Œ์•„๊ฐ€๋ณด์ž.

์ผ๋ฐ˜ ํ•จ์ˆ˜ vs Async ํ•จ์ˆ˜

์ด ๋‘๊ฐ€์ง€ ์˜ˆ๋ฅผ ์‚ดํŽด๋ณด์ž. ๋‘ ์˜ˆ ๋ชจ๋‘ ๋‘๊ฐœ์˜ ์ˆซ์ž๋ฅผ ๋”ํ•œ๋‹ค. ํ•˜๋‚˜๋Š” ์ผ๋ฐ˜์ ์ธ ํ•จ์ˆ˜ ํ†ตํ•ด ์ถ”๊ฐ€ํ•˜๊ณ , ๋‹ค๋ฅธ ํ•˜๋‚˜๋Š” ์›๊ฒฉ์œผ๋กœ ์ถ”๊ฐ€ ํ•œ๋‹ค.

๋‘๊ฐœ์˜ ์ˆซ์ž๋ฅผ ๋”ํ•˜๋Š” ์ผ๋ฐ˜ ํ•จ์ˆ˜

// add two numbers normally

function add (num1, num2) {
    return num1 + num2;
}

const result = add(1, 2); // you get result = 3 immediately

๋‘๊ฐœ์˜ ์ˆซ์ž๋ฅผ ๋”ํ•˜๋Š” Async ํ•จ์ˆ˜

// add two numbers remotely

// get the result by calling an API
const result = getAddResultFromServer('http://www.example.com?num1=1&num2=2');
// you get result  = "undefined"

์ผ๋ฐ˜ ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•˜์—ฌ ์ˆซ์ž๋ฅผ ๋”ํ•˜๋ฉด ๊ฒฐ๊ณผ๊ฐ€ ์ฆ‰์‹œ ๋‚˜ํƒ€๋‚œ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ Async ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•ด ์›๊ฒฉ ํ˜ธ์ถœ์„ ํ•˜๋ฉด ๊ธฐ๋‹ค๋ ค์•ผํ•˜๋ฉฐ ๊ฒฐ๊ณผ๋ฅผ ์ฆ‰์‹œ ์–ป์„ ์ˆ˜ ์—†๋‹ค.

์ด๋Ÿฐ ์‹์œผ๋กœ ์ž‘์—…ํ•˜๊ฒŒ ๋˜๋ฉด ์„œ๋ฒ„๊ฐ€ ๋‹ค์šด๋˜๊ฑฐ๋‚˜ ์‘๋‹ต ์†๋„๊ฐ€ ๋Š๋ ค์ ธ ๊ฒฐ๊ณผ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์„์ง€ ๋ณด์žฅํ•  ์ˆ˜ ์—†๋‹ค. ๋˜ํ•œ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๋™์•ˆ ์ „์ฒด ํ”„๋กœ์„ธ์Šค๊ฐ€ ์ฐจ๋‹จ๋˜๋Š” ๊ฒƒ์„ ์›ํ•˜์ง€ ์•Š์„ ๊ฒƒ์ด๋‹ค.

API ํ˜ธ์ถœ, ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ, ํŒŒ์ผ ์ฝ๊ธฐ๋Š” ์ผ๋ฐ˜์ ์ธ ๋น„๋™๊ธฐ ์ž‘์—… ์ค‘ ํ•˜๋‚˜์ด๋‹ค.

ํ”„๋ผ๋ฏธ์Šค ์ด์ „์˜ ์„ธ๊ณ„: Callback

๋น„๋™๊ธฐ ํ˜ธ์ถœ์— ๊ผญ ํ”„๋ผ๋ฏธ์Šค๋ฅผ ์‚ฌ์šฉํ•ด์•ผํ• ๊นŒ? ๊ทธ๊ฑด ์•„๋‹ˆ๋‹ค. ํ”„๋ผ๋ฏธ์Šค๊ฐ€ ์†Œ๊ฐœ๋˜๊ธฐ ์ด์ „์—” ์ฝœ๋ฐฑ์„ ์‚ฌ์šฉํ–ˆ๋‹ค. ์ฝœ๋ฐฑ์€ ๋ฐ˜ํ™˜ ๊ฒฐ๊ณผ๋ฅผ ์–ป์„ ๋•Œ ํ˜ธ์ถœํ•˜๋Š” ํ•จ์ˆ˜์ด๋‹ค. ์ด์ „ ์˜ˆ์ œ๋ฅผ ์ฝœ๋ฐฑ์„ ์ด์šฉํ•˜๋„๋ก ์ˆ˜์ • ํ•ด ๋ณด์ž.

// add two numbers remotely
// get the result by calling an API

function addAsync (num1, num2, callback) {
    // use the famous jQuery getJSON callback API
    return $.getJSON('http://www.example.com', {
        num1: num1,
        num2: num2
    }, callback);
}

addAsync(1, 2, success => {
    // callback
    const result = success; // you get result = 3 here
});

์œ„์˜ ๊ตฌ๋ฌธ์€ ๊ดœ์ฐฎ์•„๋ณด์ธ๋‹ค. ๊ทธ๋Ÿผ ์™œ ํ”„๋ผ๋ฏธ์Šค๋ฅผ ์จ์•ผํ• ๊นŒ?

๋น„๋™๊ธฐ ์ž‘์—… ์ดํ›„ ๋˜๋‹ค๋ฅธ ๋น„๋™๊ธฐ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋ ค๋Š” ๊ฒฝ์šฐ์—” ์–ด๋–กํ•˜์ง€?

์ˆซ์ž๋ฅผ ํ•œ๋ฒˆ๋งŒ ๋”ํ•˜์ง€ ์•Š๊ณ  3๋ฒˆ์„ ๋”ํ•ด๋ณด๋ ค๊ณ ํ•œ๋‹ค. ์ผ๋ฐ˜ ํ•จ์ˆ˜์—์„  ๋‹ค์Œ๊ณผ ๊ฐ™์ดํ•œ๋‹ค.

// add two numbers normally

let resultA, resultB, resultC;

 function add (num1, num2) {
    return num1 + num2;
}

resultA = add(1, 2); // you get resultA = 3 immediately
resultB = add(resultA, 3); // you get resultB = 6 immediately
resultC = add(resultB, 4); // you get resultC = 10 immediately

console.log('total' + resultC);
console.log(resultA, resultB, resultC);

์ฝœ๋ฐฑ์„ ์‚ฌ์šฉํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ?

// add two numbers remotely
// get the result by calling an API

let resultA, resultB, resultC;

function addAsync (num1, num2, callback) {
    // use the famous jQuery getJSON callback API
    return $.getJSON('http://www.example.com', {
        num1: num1,
        num2: num2
    }, callback);
}

addAsync(1, 2, success => {
    // callback 1
    resultA = success; // you get result = 3 here

    addAsync(resultA, 3, success => {
        // callback 2
        resultB = success; // you get result = 6 here

        addAsync(resultB, 4, success => {
            // callback 3
            resultC = success; // you get result = 10 here

            console.log('total' + resultC);
            console.log(resultA, resultB, resultC);
        });
    });
});

์˜ˆ์ œ: https://jsbin.com/barimo/edit?html,js,console

์ด ๊ตฌ๋ฌธ์€ ์นœ์ˆ™ํ•˜์ง€ ์•Š๋‹ค. ํ”ผ๋ผ๋ฏธ๋“œ ์ฒ˜๋Ÿผ ๋ณด์ด์ง€๋งŒ ์‚ฌ๋žŒ๋“ค์€ ์ฃผ๋กœ ์ด๊ฒƒ์„ "์ฝœ๋ฐฑ ์ง€์˜ฅ"์ด๋ผ ๋ถ€๋ฅธ๋‹ค. ์ฝœ๋ฐฑ์€ ๋˜๋‹ค๋ฅธ ์ฝœ๋ฐฑ์— ์ค‘์ฒฉ๋˜์–ด์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ฝœ๋ฐฑ์ด 10๊ฐœ๊ฐ€ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๋ฉด, ์ฝœ๋ฐฑ์€ 10๋ฒˆ ์ค‘์ฒฉ๋œ๋‹ค!

์ฝœ๋ฐฑ ์ง€์˜ฅ์—์„œ ๋ฒ—์–ด๋‚˜๊ธฐ

ํ”„๋ผ๋ฏธ์Šค๋Š” ์ฝœ๋ฐฑ ์ง€์˜ฅ์„ ๋ฒ—์–ด๋‚˜๊ฒŒํ•ด์ค„ ๊ตฌ์›์ž์ด๋‹ค. ๊ฐ™์€ ์˜ˆ์ œ๋ฅผ ํ”„๋ผ๋ฏธ์Šค๋กœ ๊ตฌํ˜„ํ•ด ๋ณด์ž.

// add two numbers remotely using observable

let resultA, resultB, resultC;

function addAsync(num1, num2) {
    // use ES6 fetch API, which return a promise
    return fetch(`http://www.example.com?num1=${num1}&num2=${num2}`)
        .then(x => x.json());
}

addAsync(1, 2)
    .then(success => {
        resultA = success;
        return resultA;
    })
    .then(success => addAsync(success, 3))
    .then(success => {
        resultB = success;
        return resultB;
    })
    .then(success => addAsync(success, 4))
    .then(success => {
        resultC = success;
        return resultC;
    })
    .then(success => {
        console.log('total: ' + success)
        console.log(resultA, resultB, resultC)
    });

์˜ˆ์ œ: https://jsbin.com/qafane/edit?js,console

ํ”„๋ผ๋ฏธ์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ฝœ๋ฐฑ์„ then๋กœ ํ‰ํƒ„ํ™”ํ•œ๋‹ค. ์ฝœ๋ฐฑ ์ค‘์ฒฉ์ด ์—†๊ธฐ ๋•Œ๋ฌธ์— ๋งค์šฐ ๊น”๋”ํ•ด ๋ณด์ธ๋‹ค. ๋ฌผ๋ก  ES7 ๋น„๋™๊ธฐ ๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ•˜๋ฉด์ด ์˜ˆ์ œ๋ฅผ ๋”์šฑ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜๋Š” ์žˆ์ง€๋งŒ ๊ทธ๊ฑด ์—ฌ๋Ÿฌ๋ถ„์˜ ๋ชซ์œผ๋กœ ๋‚จ๊ธด๋‹ค :)

์ƒˆ๋กœ์šด ๋…€์„: Observables

ํ”„๋ผ๋ฏธ์Šค๋กœ ์ •์ฐฉํ•˜๊ธฐ ์ „์—, Observables๋ผ๊ณ  ๋ถˆ๋ฆฌ๋Š” ๋น„๋™๊ธฐ ๋ฐ์ดํ„ฐ๋ฅผ ํ›จ์”ฌ ๋” ์‰ฝ๊ฒŒ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ๊ฒŒํ•˜๋Š” ๊ฒƒ์ด ์žˆ๋‹ค.

Observables๋Š” 0 ๊ฐœ ์ด์ƒ์˜ ์ด๋ฒคํŠธ๋ฅผ ์ƒ์„ฑ ๋˜๋Š” ์™„๋ฃŒ ๋˜๋Š” ์™„๋ฃŒ๋˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ๋Š” lazy ์ด๋ฒคํŠธ ์ŠคํŠธ๋ฆผ์ด๋‹ค. source

ํ”„๋ผ๋ฏธ์Šค์™€ Observables์˜ ์ฃผ์š” ์ฐจ์ด์ ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

๋‘๋ ค์›Œ ๋ง๊ณ  Observables๋กœ ์ž‘์„ฑ๋œ ๋™์ผํ•œ ์˜ˆ์ œ๋ฅผ ๋ณด์ž. ์ด ์˜ˆ์ œ์—์„œ๋Š” Observable๋ฅผ ์œ„ํ•ด RxJS๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

let Observable = Rx.Observable;
let resultA, resultB, resultC;

function addAsync(num1, num2) {
    // use ES6 fetch API, which return a promise
    const promise = fetch(`http://www.example.com?num1=${num1}&num2=${num2}`)
        .then(x => x.json());

    return Observable.fromPromise(promise);
}

addAsync(1,2)
  .do(x => resultA = x)
  .flatMap(x => addAsync(x, 3))
  .do(x => resultB = x)
  .flatMap(x => addAsync(x, 4))
  .do(x => resultC = x)
  .subscribe(x => {
    console.log('total: ' + x)
    console.log(resultA, resultB, resultC)
  });

์˜ˆ์ œ: https://jsbin.com/dosaviwalu/edit?js,console

Observables์€ ์ข€ ๋” ํŽ‘ํ‚คํ•˜๊ณ  ์‰ฝ๊ฒŒ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์ฝ”๋“œ ํ•œ ์ค„ ๋งŒ์œผ๋กœ add ํ•จ์ˆ˜๋ฅผ 3์ดˆ ์ง€์—ฐํ•˜๊ฑฐ๋‚˜ ํŠน์ • ํšŸ์ˆ˜์˜ ํ˜ธ์ถœ์„ ์žฌ์‹œ๋„ํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

...

addAsync(1,2)
  .delay(3000) // delay 3 seconds
  .do(x => resultA = x)
  ...

๋‹ค์Œ ๊ธ€์—์„œ Observables์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•ด ๋ณด์ž!

์š”์•ฝ

์ฝœ๋ฐฑ ๋ฐ ํ”„๋ผ๋ฏธ์Šค์— ์ต์ˆ™ํ•ด ์ ธ๋ผ. ์ด๊ฒƒ๋“ค์„ ์ดํ•ดํ•˜๊ณ  ์‚ฌ์šฉํ•ด๋ผ. Observables์— ๋Œ€ํ•ด์„œ๋Š” ์•„์ง ๊ฑฑ์ •ํ•˜์ง€ ๋ง๊ณ ! ์„ธ ๊ฐ€์ง€ ๋ชจ๋‘ ์ƒํ™ฉ์— ๋”ฐ๋ผ ๊ฐœ๋ฐœ์— ์˜ํ–ฅ์„ ์ค„ ์ˆ˜ ์žˆ๋‹ค.

์ด ๊ธ€์ด JavaScript ํ”„๋ผ๋ฏธ์Šค๋ฅผ ๋ฐฐ์šฐ๋Š” ๊ฒƒ์— ๋„์›€์ด ๋์œผ๋ฉด ์ข‹๊ฒ ๋‹ค. Happy coding!