Skip to content

Latest commit

Β 

History

History
396 lines (300 loc) Β· 11.5 KB

Async-Await.md

File metadata and controls

396 lines (300 loc) Β· 11.5 KB

Async-Await

Async-Await에 λ„λ‹¬ν•˜κΈ° μœ„ν•΄μ„œ

  1. Iterator
  2. Generator
  3. Promise
  4. Async-Await

λ¨Όμ € πŸ˜„

그전에 κ°€μž₯ λ¨Όμ € for-of에 λŒ€ν•΄μ„œ μ•Œμ•„λ³΄μž
μš°λ¦¬κ°€ ν”νžˆ μ‚¬μš©ν•˜κ³  많이 μ‚¬μš©ν•˜λŠ” for문이 μžˆλ‹€. κ·ΈλŸ¬λ‚˜ μ–΄λ””μ„œλΆ€ν„° μ–΄λ””κΉŒμ§€ 지정을 ν•˜λŠ”κ²ƒμ΄ μ•„λ‹Œ 전체λ₯Ό μˆœνšŒν•œλ‹€κ³  ν•˜λ©΄ for-inμ΄λ‚˜ foreachλ₯Ό μ‚¬μš©ν•œλ‹€.
for-in은 각각의 keyλ₯Ό λ°›μ•„μ™€μ„œ κ·Έ ν‚€λ₯Ό 가지고 valueλ₯Ό κ°€μ Έμ™€μ•Όν•˜λ©° foreachλŠ” 쀑간에 λ‚˜μ˜¬ 수 μ—†λ‹€λŠ” 단점을 가지고 μžˆλ‹€.

μ΄λŸ¬ν•˜μ—¬ 생긴것이 for-of 이닀.

ECMA2015에 μƒˆλ‘œμš΄ λ¬Έλ²•μœΌλ‘œ μΆ”κ°€κ°€ λ˜μ—ˆμœΌλ©° 이것은 배열은 λ¬Όλ‘  objectκΉŒμ§€ μˆœνšŒκ°€ κ°€λŠ₯ν•˜λ‹€.(λ¬Όλ‘  keyκ°€ μžˆμ–΄μ•Ό κ°€λŠ₯)

for-of문은 μ—΄κ±°κ°€ κ°€λŠ₯ν•œ 객체라면 무엇이든 μˆœνšŒκ°€ κ°€λŠ₯ν•˜λ‹€.

κ·Έλ ‡λ‹€λ©΄ μ—΄κ±°κ°€λŠ₯ν•œ κ°μ²΄λž€ 무엇인가?

πŸ‘‰ λ°°μ—΄(Array)λŠ” λ¬Όλ‘ , TypedArray, λ¬Έμžμ—΄(String), Map, Set, DOM Collection 등을 λ§ν•œλ‹€.


/* array */
let iterable = [10, 20, 30];

for (let value of iterable) {
    console.log(value); // 10 20 30
}

/* string */
let iterable = "boo";

for (let value of iterable) {
    console.log(value); // "b" "o" "o"
}

/* Typed Array */
let iterable = new Uint8Array([0x00, 0xff]);

for (let value of iterable) {
    console.log(value); // 0 255
}

/* Map */
let iterable = new Map([["a", 1], ["b", 2], ["c", 3]]);

for (let entry of iterable) {
    console.log(entry); // [a, 1] [b, 2] [c, 3]
}

for (let [key, value] of iterable) {
    console.log(value); // 1 2 3
}

/* Set */
let iterable = new Set([1, 1, 2, 2, 3, 3]);

for (let value of iterable) {
    console.log(value); // 1 2 3
}

/* DOM Collection */
let articleParagraphs = document.querySelectorAll("article > p");

for (let paragraph of articleParagraphs) {
    paragraph.classList.add("read");
}

μ–΄λ–»κ²Œ 순회λ₯Ό ν•  수 μžˆλŠ” κ²ƒμΌκΉŒ ❔

πŸ‘‰ iterator 덕뢄이닀.

Collection듀은 λ‚΄λΆ€μ μœΌλ‘œ Iterable Protocol을 κ΅¬ν˜„ν•œλ‹€.

Iterable Protocol

어떀객체가 μˆœνšŒκ°€ 되기 μœ„ν•΄μ„œλŠ” iterationλ™μž‘μ— λŒ€ν•΄ μ •μ˜κ°€ λ˜μ–΄ μžˆμ–΄μ•Ό ν•œλ‹€.

Iterable Protocol에 μ˜ν•˜λ©΄ IteratorλŠ” next()ν•¨μˆ˜λ₯Ό κ΅¬ν˜„ν•΄μ•Όν•˜κ³  이 ν•¨μˆ˜λŠ” κ²°κ³Όκ°’μœΌλ‘œ {value: value, doen: boolean} 같은 객체λ₯Ό λ°˜ν™˜ν•΄μ•Ό ν•œλ‹€κ³  ν•œλ‹€.

Ex) κ΅¬ν˜„ν•΄λ³΄κΈ°

function makeRangeIterator(start = 0, end = Infinity, step = 1) {
    var nextIndex = start;
    var n = 0;

    var rangeIterator = {
        next: function() {
            var result;

            if (nextIndex < end) {
                result = { value: nextIndex, done: false }
            } else if (nextIndex == end) {
                result = { value: n, done: true }
            } else {
                result = { done: true };
                nextIndex += step;
                n++;
                return result;
            }
        };
    return rangeIterator;
}

// run iterator
const it = makeRangeIterator(1, 4);
let result = it.next();// 처음 ν•œλ²ˆ μ‹€ν–‰

while (!result.done) {
    console.log(result.value); // 1 2 3
    result = it.next();
}

ECMA2015μ—μ„œλŠ” Iterator protocol을 μ΄μš©ν•˜μ—¬ μ—΄κ±°κ°€λŠ₯ν•œ 객체λ₯Ό λ§Œλ“€ 수 μžˆλ‹€.

[Symbol.iterator]() 와 next()λ₯Ό μ΄μš©ν•˜λ©΄ μ‰½κ²Œ μ •μ˜ν•  수 μžˆλ‹€.

for-ofλŠ” [Symbol.iterator]()λ₯Ό ν˜ΈμΆœν•˜μ—¬ λ°˜λ³΅μ„ μ‹€ν–‰ν•˜κ²Œ λœλ‹€.

예제 πŸ‘‡

const iterable = {
    [Symbol.iterator]() {
        return {
            i: 0,
            next() {
                if (this.i < 3) {
                    return { value: this.i++, done: false };
                }

                return { value: undefined, done: true };
            }
        };
    }
};

for (var value of iterable) {
    console.log(value); // 0 1 2
}


Generator

Iterator와 λΉ„μŠ·ν•œ 이녀석은 μΌμ’…μ˜ **코루틴(Co-Routine)**인데, λ‹€λ₯Έ μ–Έμ–΄μ—μ„œλŠ” 곧 잘 μ‚¬μš©ν•˜λŠ” κ°œλ…μ΄λ‹€.

코루틴(Co-Routine) : μ–΄λŠ μž‘μ—…μ„ ν•˜λ‹€κ°€ 쀑간에 λ©ˆμΆ”κ³  λ©ˆμΆ˜λΆ€λΆ„λΆ€ν„° λ‹€μ‹œ μ‹œμž‘μ΄ κ°€λŠ₯ν•œ


GeneratorλŠ” ν•¨μˆ˜ 싀행도쀑에 μž μ‹œ λ©ˆμ·„λ‹€κ°€ λ‹€μ‹œ μ‹€ν–‰ν•  수 μžˆλŠ” λ…νŠΉν•œ ν•¨μˆ˜μ΄λ‹€. GeneratorλŠ” function*ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•΄μ„œ μƒμ„±ν•˜λ©°,

Generatorλ₯Ό ν˜ΈμΆœν•˜λ©΄ μ‹€ν–‰λ˜λŠ” 것이 μ•„λ‹ˆλΌ Iterator객체가 λ°˜ν™˜λœλ‹€.

λ”°λΌμ„œ Iteratorμ—μ„œ κ΅¬ν˜„ν•œ next() ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜λ©΄ Generatorκ°€ μ‹€ν–‰λ˜λ©΄μ„œ yieldλ₯Ό λ§Œλ‚  λ•ŒκΉŒμ§€ μ‹€ν–‰λ˜κ³ , μ΄λ•Œ μ»¨ν…μŠ€νŠΈλŠ” μ €μž₯된 μƒνƒœλ‘œ 남아 있게 λœλ‹€.

예제 πŸ‘‡

function* idMaker(){
    var index = 0;
    while(index < 3)
        yield index++;
}

const gen = idMaker(); // iterator객체가 λ°˜ν™˜

console.log(get.next());
console.log(get.next());
console.log(get.next());

Generatorλ₯Ό μ‚¬μš©ν•˜λ©΄ Iterable Protocol을 κ΅¬ν˜„ν•˜λŠ” 것보닀 μ’€ 더 μ‰½κ²Œ Iteratorλ₯Ό μ‚¬μš©ν•  수 μžˆλ‹€.

Generator의 진면λͺ©μ€ 비동기 ν”„λ‘œκ·Έλž˜λ°μ—μ„œ λ³Ό 수 μžˆλ‹€. ν•¨μˆ˜κ°€ μ‹€ν–‰ 도쀑에 λ©ˆμΆ˜λ‹€λ‹ˆ. μ–Έμ œ 응닡이 μ˜¬μ§€ μ•Œ 수 μ—†κΈ° λ•Œλ¬Έμ—, callback을 λ“±λ‘ν•˜λŠ” 비동기 ν”„λ‘œκ·Έλž˜λ°μ— μ‘μš©ν•˜λ©΄ callback hell을 νƒˆμΆœν•  수 μžˆμ§€ μ•Šμ„κΉŒ?

generator도 μ—­μ‹œ ES5μŠ€νŽ™μ΄ μ•„λ‹ˆλ‹€ ES6이닀.
κ·Έλ ‡λ‹€λ©΄ GeneratorλŠ” 또 μ–΄λ–»κ²Œ κ΅¬ν˜„μ΄ λ˜μ–΄μžˆλŠ” 것인가?

// ES6
function* foo(){
    yield bar();
}

// ES5 Compiled
"use strict";

var _marked = /*#__PURE__*/ regeneratorRuntime.mark(foo);

function foo() {
    return regeneratorRuntime.wrap(
        function foo$(_context) {
            while (1) {
                switch ((_context.prev = _context.next)) {
                    case 0:
                        _context.next = 2;
                        return bar();
                    case 2:
                    case "end":
                        return _context.stop();
                }
            }
        },
        _marked, this
    );
}

GenratorλŠ” κ²°κ΅­ iterable Protocelλ₯Ό κ΅¬ν˜„ν•˜λŠ” 객체이닀. κ·ΈλŸ¬λ‚˜ ν”„λ‘œν† μ½œκ³Ό κ΄€λ ¨λœ μ–΄λŠκ²ƒλ„ 보이지 μ•ŠλŠ”λ‹€.

λŒ€μ‹  regeneratorRuntime이것이 보인닀.

babelμ—μ„œλŠ” regeneratorRuntime라이브러리λ₯Ό μ‚¬μš©ν•΄μ„œ κ΅¬ν˜„μ„ ν–ˆλ‹€.

μ½”λ“œμ˜ 역사λ₯Ό 따라가닀 보면 facebook/regenerator repository에 λ„λ‹¬ν•˜κ²Œ λœλ‹€.

https://github.com/facebook/regenerator/blob/master/packages/regenerator-runtime/runtime.js


이 λΌμ΄λΈŒλŸ¬λ¦¬λŠ” 2013λ…„ Node.js v0.11.2μ—μ„œ generator syntaxλ₯Ό μ§€μ›ν•˜κΈ° μœ„ν•΄ λ§Œλ“€μ–΄ 쑌으며, Babelμ—μ„œλŠ” 이 라이브러리λ₯Ό μ‚¬μš©ν•˜μ—¬ generatorλ₯Ό κ΅¬ν˜„ν•˜κ³  μžˆλ‹€. μ‹€μ œ μ½”λ“œλ₯Ό 듀여닀보면 Symbolκ³Ό Iteratorλ₯Ό μ΄μš©ν•΄μ„œ Iterable Protocol을 κ΅¬ν˜„ν•˜κ³  μžˆλ‹€.

Async-await

이제 본둠으둜 λŒμ•„μ™€μ„œ Async-await은 μ–΄λ–»κ²Œ κ΅¬ν˜„μ΄ λ˜μ—ˆλŠ”κ°€??

Async-awaitλŠ” ECMA-262μ—μ„œ μ΄ˆμ•ˆμœΌλ‘œ 처음 λ“±μž₯ν–ˆμœΌλ©°, ECMAScript 2017μ—μ„œ ν‘œμ€€μœΌλ‘œ μ •μ˜λ˜μ—ˆλ‹€.(ES8μ—μ„œ ν‘œμ€€μ΄ λ˜μ—ˆλ‹€.)

λ¨Όμ € Babelμ—μ„œ Async-awaitλ₯Ό 돌리게 되면 ES5λ²„μ „μœΌλ‘œ λ‚˜μ˜¨λ‹€. κ·Έλ ‡λ‹€λ©΄ ES5둜 κ΅¬ν˜„μ΄ κ°€λŠ₯ν•˜λ‹€λŠ” 것이닀. μ‹€μ œλ‘œ Babel둜 돌리게 되면 μ•„λž˜μ™€ 같은 κ²°κ³Όκ°€ λ‚˜μ˜¨λ‹€.

// ES7
async function foo() {
    await bar();
}

// ES5 complied
let foo = (() => {
   var _ref = _asyncToGenerator(function*() {
       yield bar();
   });

    return function foo() {
       return _ref.apply(this, arguments);
    };
})();

function _asyncToGenerator(fn) {
    return function() {
        var gen = fn.apply(this, arguments);

        return new Promise(function(resolve, reject) {
            function step(key, arg) {
                try {
                    var info = gen[key](arg);
                    var value = info.value;
                } catch (error) {
                    reject(error);
                    return;
                }

                if (info.done) {
                    resolve(value);
                } else {
                    return Promise.resolve(value).then(
                        function(value) {
                            step("next", value);
                        },
                        function(err) {
                            step("throw", err);
                        }
                    );
                }
            }
            return step("next");
        });
    };
}

μœ„μ— 컴파일됨 ꡬ문을 보게 되면 async keywordλ₯Ό generator둜 λ°”κΎΈκ³  await keywordλŠ” yield둜 λ°”κΎΈμ—ˆλ‹€.

GeneratorλŠ” yieldλ₯Ό λ§Œλ‚  λ•ŒκΉŒμ§€ μ‹€ν–‰λœλ‹€. μ΄λ•Œ ContextλŠ” μ €μž₯된 μƒνƒœλ‘œ λ‚¨μ•„μžˆκ²Œ λœλ‹€.

즉 Generator둜 비동기 둜직이 λλ‚ λ•Œλ§ˆλ‹€ 적절히 next()λ₯Ό μ μ ˆν•˜κ²Œ ν˜ΈμΆœν•΄μ£Όλ©΄ Async-Awaitν•¨μˆ˜κ°€ λ§Œλ“€μ–΄ μ§€λŠ” 것이닀.

κ·ΈλŸ¬λ‚˜ bar()ν•¨μˆ˜μ˜ μž‘μ—…μ΄ μ’…λ£Œλ˜λŠ” μ‹œμ μ€ bar()ν•¨μˆ˜λ°–μ— λͺ¨λ₯Έλ‹€. κ·Έλ ‡λ‹€κ³  next()λ₯Ό bar()ν•¨μˆ˜ λ‚΄μ—μ„œ 직접 μ‹€ν–‰ν•˜κ²Œ λœλ‹€λ©΄ μ˜μ‘΄μ„±μ΄ μƒκΈ°κ²Œ λœλ‹€.

κ·Έλ ‡λ‹€λ©΄ μ–΄λ–»κ²Œ μ˜μ‘΄μ„±μ„ 뢄리 ν•  수 μžˆμ„κΉŒ?

⭐⭐ Promise ⭐⭐

Babel은 promise와 μž¬κ·€ν•¨μˆ˜λ₯Ό μ΄μš©ν•˜μ—¬ next()λ₯Ό λŒ€μ‹  ν˜ΈμΆœν•΄μ£ΌλŠ” ν•¨μˆ˜λ₯Ό λ§Œλ“œλŠ”λ°, 그게 λ°”λ‘œ _asyncToGenerator이닀.

fn.applyλ₯Ό μ‹€ν–‰ν•˜μ—¬ 인자둜 λ„˜μ–΄μ˜¨ Generatorλ₯Ό μ‹€ν–‰ν•˜μ—¬ iterator객체λ₯Ό ν΄λ‘œμ €λ‘œ μ €μž₯ν•΄λ‘”λ‹€. λ‚˜λ¨Έμ§€λŠ” ν΄λ‘œμ €μ— μ €μž₯ν•œ iteratorλ₯Ό μ‹€ν–‰μ‹œν‚€κ³ , λ°˜ν™˜λœ promise객체λ₯Ό μž¬κ·€ν•¨μˆ˜λ₯Ό ν† ν•΄ λ°˜λ³΅μ‹€ν–‰

μ •λ¦¬ν•˜μžλ©΄ GeneratorλŠ” 비동기적 νŒ¨ν„΄μ„ yieldλ₯Ό 톡해 동기적인 β€œλͺ¨μŠ΅"으둜 λ°”κΎΈμ–΄μ£Όκ³ , PromiseλŠ” Generator둜 λ§Œλ“  iteratorλ₯Ό λ°˜λ³΅ν•΄μ„œ μ‹€ν–‰ν•΄μ£ΌλŠ” 역할을 ν•œλ‹€. await keyword에 μ‚¬μš©ν•˜λŠ” ν•¨μˆ˜κ°€ 항상 promiseλ₯Ό λ°˜ν™˜ν•΄μ•Όν•˜λŠ” μ΄μœ κ°€ 여기에 μžˆλ‹€.

Promise => ν”„λ‘œλ―ΈμŠ€λŠ” μžλ°”μŠ€ν¬λ¦½νŠΈ 비동기 μ²˜λ¦¬μ— μ‚¬μš©λ˜λŠ” κ°μ²΄μž…λ‹ˆλ‹€. μ—¬κΈ°μ„œ μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ 비동기 μ²˜λ¦¬λž€ β€˜νŠΉμ • μ½”λ“œμ˜ 싀행이 μ™„λ£Œλ  λ•ŒκΉŒμ§€ 기닀리지 μ•Šκ³  λ‹€μŒ μ½”λ“œλ₯Ό λ¨Όμ € μˆ˜ν–‰ν•˜λŠ” μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ νŠΉμ„±β€™μ„ μ˜λ―Έν•©λ‹ˆλ‹€


πŸ‘‰ Promise둜만 κ΅¬ν˜„ν•  경우

const makeRequest = () => {
    return getJSON()
        .then(data => {
            if (data.needsAnotherRequest) {
                return makeAnotherRequest(data)
                    .then(moreData => {
                        console.log(moreData)
                        return moreData
                    })
            } else {
                console.log(data)
                return data
            }
        })
}

πŸ‘‰ async-await둜 κ΅¬ν˜„ν•  경우

const makeRequest = async () => {
    const data = await getJSON()

    if (data.needsAnotherRequest) {
        const moreData = await makeAnotherRequest(data);
        console.log(moreData)
        return moreData
    } else {
        console.log(data)
        return data
    }
}


μ°Έκ³