Asynchronous Processing in JavaScript

--- title: 'Asynchronous Processing in JavaScript' author: 'Hun Im' date: 2022-05-05T19:53:35+09:00 category: ['POSTS'] tags: ['Javascript'] og_image: "/images/gamer.png" keywords: ['Javascript'] --- **Promise** The Promise object, introduced in JavaScript ES6, was first created to solve the "callback hell" problem, which arises when callback functions accumulate during asynchronous operations. While it works on the same principle, the Promise object provides better readability, which is why it is utilized. However, using many promise variables can lead to experiencing "promise hell" as well. **Response Time of Callback Functions, Promises, and Async/Await** The response time for both callback functions and promises is almost identical. They are read sequentially in the initial hoisting environment, causing the asynchronous part to be read before the previous processes are complete. Thus, even if there is a delay with functions like setTimeout, the response time disregards the delay and processes the next lines first. The reason the response time for callback functions and promises is almost the same is due to slight speed differences caused by the browser's environment. Overall, the response time for async/await is the slowest because it waits for all asynchronous tasks (like setTimeout) to finish before proceeding in order. **Callback Functions** To understand callback functions, one must first understand "hoisting." **Hoisting** Hoisting is the process of elevating all declarations within a function to the top of the function's scope. *All necessary values for the function are declared at the top before the function executes.* **setTimeout(callback , time)** A browser API that outputs the callback function after a specified time (in milliseconds). **Synchronous vs. Asynchronous** JavaScript is synchronous. Synchronous callback ```jsx console.log('1') setTimeout(() => console.log('2'), 1000) console.log('3') function printImmediately(print) { print() } printImmediately(() => console.log('hello')) ``` Hoisting result: ```jsx function printImmediately(print) { // 1. Hoisting function declaration print() } console.log('1') // 2. Outputs '1' setTimeout(() => console.log('2'), 1000) // 3. Requests to output '2' after 1 second console.log('3') // 4. Outputs '3' printImmediately(() => console.log('hello')) // 5. Immediately executes function, outputs 'hello' // 6. Outputs '2' after 1 second, per browser API ``` Asynchronous callback ```jsx console.log('1') setTimeout(() => console.log('2'), 1000) console.log('3') function printImmediately(print) { print() } printImmediately(() => console.log('hello')) function printWithDelay(print, timeout) { setTimeout(print, timeout) } printWithDelay(() => console.log('async callback'), 2000) ``` Hoisting result: ```jsx function printImmediately(print) { print() } function printWithDelay(print, timeout) { setTimeout(print, timeout) } console.log('1') // Synchronous setTimeout(() => console.log('2'), 1000) // Asynchronous ------------> console.log('3') // Synchronous printImmediately(() => console.log('hello')) // Synchronous printWithDelay(() => console.log('async callback'), 2000) // Asynchronous ------------> ``` **Promise** A Promise is "an object that can handle asynchronous states as values." **Why are promises needed?** Promises are mainly used to display data received from servers. Generally, when implementing web applications, APIs are used to request and retrieve data from servers. **Problems with Callback Patterns** 1. Nested use of callback functions ```jsx function requestData1(callback) { callback(data) // 2 } function requestData2(callback) { callback(data) // 4 } function onSuccess1(data) { console.log(data) requestData2(onSuccess2) // 3 } function onSuccess2(data) { // 5 console.log(data) } requestData1(onSuccess1) // 1 // The flow of callback pattern code is not sequential, making it hard to read. ``` 2. Simple Promise code example ```jsx requestData1() .then((data) => { console.log(data) return requestData2() }) .then((data) => { console.log(data) }) ``` 3. Three states of a Promise - pending: waiting - fulfilled: completed normally with a result - rejected: completed abnormally. - settled: either fulfilled or rejected state. Once a promise is settled, it cannot change to another state. It can only change from pending to fulfilled or rejected. 4. How to create a Promise ```js const p1 = new Promise((resolve, reject) => { resolve(data) // or reject('error message') }) const p2 = Promise.reject('error message') const p3 = Promise.resolve(param) ``` 5. Promise.resolve return value ```js const p1 = Promise.resolve(123) console.log(p1 !== 123) // true ์ดํ–‰๋จ ์ƒํƒœ์ธ ํ”„๋กœ๋ฏธ์Šค๊ฐ€ ๋ฐ˜ํ™˜๋œ๋‹ค. const p2 = new Promise((resolve) => setTimeout(() => resolve(10), 1)) console.log(Promise.resolve(p2) === p2) // true // Promise.resolve ํ•จ์ˆ˜์— ํ”„๋กœ๋ฏธ์Šค๊ฐ€ ์ž…๋ ฅ๋˜๋ฉด ๊ทธ ์ž์‹ ์ด ๋ฐ˜ํ™˜๋œ๋‹ค. ``` 6. Using Promises: .then The then method is used when handling a fulfilled promise. ```js //requestData().then(onResolve, onReject); // When the promise becomes fulfilled, the onResolve function is called; if rejected, the onReject function is called. Promise.resolve(123).then((data) => console.log(data)) // 123 Promise.reject('err').then(null, (error) => console.log(error)) // err ``` 7. Chaining multiple .then calls ```js let requestData1 = new Promise((resolve, reject) => { setTimeout(() => { resolve('hun') }, 1000) }) let requestData2 = new Promise((resolve, reject) => { setTimeout(() => { resolve('jenny') }, 2000) }) requestData1 .then((data) => { console.log(data) return requestData2 // 1 }) .then((data) => { return data + 1 // 2 }) .then((data) => { throw new Error('some Error') // 3 }) .then(null, (error) => { console.log(error) }) ``` 1. When a promise is returned from a function, the then method returns that value as is. 2. If a non-promise value is returned, the then method returns a fulfilled promise. 3. If an exception occurs within the function, the then method returns a rejected promise. 4. If it becomes a rejected state, the onReject function is called. ```js Promise.reject('err') .then(() => console.log('then 1')) // 1 .then(() => console.log('then 2')) // 1 .then( () => console.log('then 3'), () => console.log('then 4') ) // 2 .then( () => console.log('then 5'), () => console.log('then 6') ) // 3 ``` Since the promise is rejected, the first encountered onReject function is called, making the first instance omitted, and the then 4 from the second code outputs. The function that prints then 4 has undefined as its result, which creates a fulfilled promise. Therefore, then 5 is printed in the subsequent then method. The most important characteristic of the then method is that it is always called in the order it is chained. 8. Using Promises 2: catch Catch is a method for handling exceptions that occur during promise execution. The catch method serves the same purpose as the onReject function of the then method. javascript ์ฝ”๋“œ ๋ณต์‚ฌ Promise.reject(1).then(null, (error) => { console.log(error) }) Promise.reject(1).catch((error) => { console.log(error) }) For readability, itโ€™s better to use the catch method for exception handling than the onReject function of then. Problems when using the onReject function of then. javascript ์ฝ”๋“œ ๋ณต์‚ฌ Promise.resolve().then( () => { // 1 throw new Error('some error') }, (error) => { // 2 console.log(error) } ) The exception raised in the resolve function of the first then is not handled by the reject function of the same then. Executing this will result in an Unhandled promise rejection error because the rejected promise was not handled. An example using catch instead of the onReject function. ```js Promise.reject(1).then(null, (error) => { console.log(error) }) Promise.reject(1).catch((error) => { console.log(error) }) ``` For readability, itโ€™s better to use the catch method for exception handling than the onReject function of then. 9. Problems when using the onReject function of then. ```js Promise.resolve().then( () => { // 1 throw new Error('some error') }, (error) => { // 2 console.log(error) } ) ``` The exception raised in the resolve function of the first then is not handled by the reject function of the same then. Executing this will result in an Unhandled promise rejection error because the rejected promise was not handled. 10. An example using catch instead of the onReject function. ```js Promise.resolve() .then(() => { throw new Error('some error') }) .catch((error) => { console.log(error) }) ``` 11. Using then after catch ```js Promise.reject(10) .then((data) => { console.log('then1:', data) return 20 }) .catch((error) => { console.log('catch:', error) return 30 }) .then((data) => { console.log('then2:', data) }) // catch: 10 // then2: 30 ``` 12. Using Promises 3: Finally - A simple code example using finally: ```js requestData() .then(data => { ... }) .catch(error => { ... }) .finally(() => { ... }); ``` - The finally method does not create a new promise. ```js function requestData(){ return fetch() .catch(error => { ... }) .finally(() => { senLogToServer('requestData finished') }) } requestData().then(data => console.log(data)); // 1๋ฒˆ ``` In the first case, the return value of the `requestData` function is the promise before the `finally` method is called. Therefore, as a user of the requestData function, you don't have to worry about the existence of the `finally` method. **Using Promises Effectively** **Handling in Parallel: Promise.all** `Promise.all` is a function used for processing multiple promises in parallel. By chaining the `then` method, you can overcome the drawback of asynchronous processes being executed sequentially. - Asynchronous code executed sequentially: ```js requestData1() .then((data) => { console.log(data) return requestData2() }) .then((data) => { console.log(data) }) ``` If there is no dependency between asynchronous functions, processing them in parallel is faster. By calling the asynchronous functions separately without chaining the then method, they will be processed in parallel. - Code executed in parallel: ```js requestData1().then((data) => { console.log(data) }) requestData2().then((data) => { console.log(data) }) ``` `requestData1` and `requestData2` run simultaneously. If you want to process multiple promises in parallel, use Promise.al - Code using `Promise.all`: ```js Promise.all([requestData1(), requestData2()]).then(([data1, data2]) => { console.log(data1, data2) }) ``` The `Promise.all` function returns a promise. The promise returned by `Promise.all` will only become fulfilled when all the input promises are fulfilled. If any promise is rejected, the promise returned by `Promise.all` will also be in the rejected state. **Getting the Fastest Processed Promise: Promise.race** When any promise input to the `Promise.race` function becomes fulfilled, the promise returned by Promise.race also becomes fulfilled. - Simple code using `Promise.race`: ```js Promise.race([ requestData(), new Promise((_, reject) => setTimeout(reject, 3000)), ]) .then((data) => console.log(data)) .catch((error) => console.log(error)) ``` If the `requestData` function receives data within 3 seconds, the `then` method is called; otherwise, the `catch` method is called. **Data Caching Using Promises** By leveraging the property of promises that maintain their state when fulfilled, you can cache data. - Implementing caching functionality with promises: ```js let cachedPromise function getData() { cachedPromise = cachedPromise || requestData() // 1๋ฒˆ return cachedPromise } getData().then((v) => console.log(v)) getData().then((v) => console.log(v)) ``` n the first instance, when the `getData` function is called for the first time, `requestData` is invoked. Once the data retrieval task is complete, the result is stored in the `cachedPromise`. **Cautions When Using Promises** - Don't forget the return keyword. It's easy to forget to input the return keyword in the internal function of the `then` method. The data of the promise object returned by the `then` method is the value returned by the internal function. If you don't use the return keyword, the data of the promise object will be undefined. - Code that forgets the return keyword: ```js Promise.resolve(10) .then((data) => { console.log(data) Promise.resolve(20) // 2๋ฒˆ }) .then((data) => { console.log(data) // 1๋ฒˆ }) ``` In the first instance, undefined is printed contrary to the intention. If you input the return keyword in the second piece of code, 20 will be printed as intended. - Remember that promises are immutable objects. Promises are immutable objects. - Code written thinking that a promise can be modified: ```js function requestData() { const p = Promise.resolve(10) p.then(() => { // 1 return 20 }) return p } requestData().then((v) => { console.log(v) // 10 // 2 }) ``` The `then` method does not modify the existing object; it returns a new promise. In the second case, if you want 20 to be printed, you need to modify the `requestData` function as follows. - Code returning the promise created by the `then` method: ```js function requestData() { return Promise.resolve(10).then((v) => { return 20 }) } ``` - Avoid using nested promises. Using nested promises can lead to "promise hell" similar to callback hell. ```js requestData1().then(result1 => { requestData2(result2 => { .... }); }); ``` This is not readable, so let's refactor it as in the following code. - Refactored code to avoid nesting: ```js requestData1() .then(result1 => { return requestData2(result1) }) .then(result2 => { return ... // 1๋ฒˆ }) ``` If you need to reference the result1 variable in the first instance, how can you do that? - You can solve the variable reference issue without nesting by using `Promise.all`. - Code solving variable reference problem using `Promise.all`: ```js requestData1() .then(result1 => { return Promise.all([result1, requestData2(result1)]) // 1 .then(([result1, result2]) => { ........... }); ``` In the first instance, if you input non-promise values into the array for the `Promise.all` function, those values will be treated as if they are fulfilled promises. **Pay Attention to Exception Handling in Synchronous Code** When using promises like synchronous (sync) code, you should pay attention to exception handling. - Code where exceptions occurring in synchronous code are not handled: ```js function requestData() { doSync() // 1 return fetch() .then((data) => console.log(data)) .catch((error) => console.log(error)) } ``` In the first instance, if the `doSync` function does not necessarily need to be called before fetch, it's better to put it inside the `then` method like this: - Code where synchronous code also handles exceptions: ```js function requestData() { return fetch() .then((data) => { doSync() console.log(data) }) .catch((error) => console.log(Error)) } ``` Exceptions occurring in `doSync` will be handled by the `catch` method. **Enhanced Asynchronous Programming: async, await** **Understanding async/await:** While promises exist as objects, async/await is a concept applied to functions. A function returning a promise using async/await: ```js async function getData() { return 123 //Promise {<fulfilled>: 123} } getData().then((data) => console.log(data)) // 123 Promise {<fulfilled>: undefined} ``` - A function returning a promise using async/await: ```js async function getData() { return Promise.resolve(123) } getData().then((data) => console.log(data)) ``` Similar to the `then` method of promises, if the value returned within the async/await function is a promise, that object will be returned as is. - Cases where exceptions occur in async/await functions: ```js async function getData() { throw new Error('123') } getData().catch((error) => console.log(error)) // Error : 123 ``` - Using the `await` keyword: ```js function requestData(value) { return new Promise((resolve) => setTimeout(() => { console.log('requestData:', value) resolve(value) }, 100) ) } async function getData() { const data1 = await requestData(10) //1 const data2 = await requestData(20) //1 console.log(data1, data2) // 2 return [data1, data2] } getData() // requestData: 10 // 3 // requestData: 20 // 3 // 10, 20 // 3 ``` In the first instance, the code in the second instance will not execute until the promise returned by `requestData` is fulfilled. Therefore, the result of calling the `getData` function is reflected in the third instance. The `async` keyword can only be used within async/await functions. Using it in a regular function will cause an error. - `await` ํ‚ค์›Œ๋“œ๋Š” async ํ‚ค์›Œ๋“œ ์—†์ด ์‚ฌ์šฉ ํ•  ์ˆ˜ ์—†๋‹ค. ```js function getData(){ const data = await requestData(10); // Error console.log(data); } ``` **async/await is more readable than promises.** - Comparing async/await and Promises ```js function getDataPromise() { asyncFunc1() .then((data) => { console.log(data) return asyncFunc2() }) .then((data) => { console.log(data) }) } // 1๋ฒˆ ํ”„๋กœ๋ฏธ์Šค๋กœ ์ž‘์„ฑํ•œ ์ฝ”๋“œ async function getDataAsync() { const data1 = await asyncFunc1() console.log(data1) const data2 = await asyncFunc2() console.log(data2) } // 2๋ฒˆ async await๋กœ ์ž‘์„ฑํ•œ ์ฝ”๋“œ ``` The code written using async/await has better readability. The reason for its conciseness is that async/await functions do not require calling the `then` method. - Comparing Readability in Highly Dependent Code ```js function getDataPromise() { return asyncFunc1() .then(data1 => Promise.all([data1, asyncFunc2(data1)])) // 1 .then([data1, data2]) => { return asyncFunc3(data1,data2); }); } async function getDataAsync() { // 2 const1 data1 = await asyncFunc1(); const2 data2 = await asyncFunc2(data1); return asyncFunc3(data1, data2); } ``` In 1, `Promise.all` is used to pass two return values to the `asyncFunc3` function. In 2, the async/await function remains intuitive even with complex dependencies. **Using async/await Effectively** - Running Asynchronous Functions in Parallel * Sequentially running asynchronous code ```js async function getData() { const data1 = await asyncFunc1() const data2 = await asyncFunc2() // ... } ``` If there are no dependencies between the two functions, it is better to run them simultaneously. Promises execute asynchronously as soon as they are created. Therefore, by creating two promises first and using the `await` keyword later, we can achieve parallel execution. - Running Asynchronous Code in Parallel by Using `await` Later ```js async function getData() { const p1 = asyncFunc1() const p2 = asyncFunc2() const data1 = await p1 const data2 = await p2 } ``` - Using `Promise.all` to Process in Parallel ```js async function getData() { const [data1, data2] = await Promise.all([asyncFunc1(), asyncFunc2()]) // .... } ``` - Handling Exceptions It is advisable to handle exceptions occurring within async/await functions using try/catch blocks. Both synchronous and asynchronous functions can be handled in the catch block. ```js async function getData() { try { await doAsync() return doSync() } catch (error) { console.log(error) } } ``` All exceptions that occur in asynchronous and synchronous functions are handled in the catch block. - Support for Thenables in async/await Thenables are objects that behave like promises. - Example of Using Thenables in async/await Functions ```js class ThenableExample { then(resolve, reject) { // 1๋ฒˆ setTimeout(() => resolve(123), 1000) } } async function asyncFunc() { const result = await new ThenableExaple() // 2๋ฒˆ console.log(result) // 123 } ``` In 1, the `ThenableExample` class has a `then` method, so any object created from the `ThenableExample` class is considered a Thenable. In 2, the async/await function treats Thenables like promises. - Difference Between sync/await and Promises Promise: Ignores the execution of the code when it is encountered and continues executing the next code. async/await: When it encounters await, it waits until the code is finished (until the request is completed, until it is not pending) before executing the next code.
ย 
--- title: '์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ์˜ ๋น„๋™๊ธฐ์ฒ˜๋ฆฌ' author: '์ž„ํ›ˆ' date: 2022-05-05T19:53:35+09:00 category: ['POSTS'] tags: ['Javascript'] og_image: "/images/gamer.png" keywords: ['Javascript'] --- **Promise** ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ES6์ดํ›„์— ๋“ฑ์žฅํ•˜๊ฒŒ ๋œ promise๊ฐ์ฒด๋Š” ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ์ž‘์—… ํ•  ๋•Œ ์ฝœ๋ฐฑํ•จ์ˆ˜๊ฐ€ ์Œ“์ด๊ฒŒ๋˜๋Š” ์ฝœ๋ฐฑ์ง€์˜ฅ์„ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์ฒ˜์Œ ๋“ฑ์žฅ์ด ๋˜์—ˆ๋‹ค. ๊ฐ™์€ ์›๋ฆฌ์ด์ง€๋งŒ, promise๊ฐ์ฒด๋ฅผ ํ†ตํ•ด ๋” ๊ฐ€๋…์„ฑ์ด ์‰ฝ๊ฒŒ ํ‘œ์‹œํ•  ์ˆ˜ ์žˆ์–ด์„œ ์ด์šฉํ•˜๊ฒŒ ๋˜์—ˆ๊ณ , promise ๋˜ํ•œ ๋งŽ์€ promise๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฆฌํ„ดํ•˜๊ฒŒ ๋˜๋ฉด promise์ง€์˜ฅ์„ ๊ฒฝํ—˜ ํ•  ์ˆ˜ ์žˆ๋‹ค. **์ฝœ๋ฐฑํ•จ์ˆ˜, promise, async/await์˜ ์‘๋‹ต์†๋„** ์ฝœ๋ฐฑํ•จ์ˆ˜๋‚˜ promise์˜ ์‘๋‹ต์†๋„๋Š” ๊ฑฐ์˜ ๊ฐ™๋‹ค. ์ฒ˜์Œ ํ˜ธ์ด์ŠคํŒ… ํ™˜๊ฒฝ์—์„œ ์ฐจ๋ก€๋กœ ์ฝ๊ธฐ ๋•Œ๋ฌธ์— ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ๋˜๋Š” ์˜์—ญ์€ ์ฒ˜๋ฆฌ ์™„๋ฃŒ ๋˜์ง€ ์•Š์€ ์ƒํƒœ์—์„œ ๋‹ค์Œ์„ ์ฝ๋Š”๋‹ค. ๋”ฐ๋ผ์„œ, setTimeoutํ•จ์ˆ˜์™€ ๊ฐ™์ด ๋”œ๋ ˆ์ด๋ฅผ ์ฃผ๊ฒŒ ๋˜์–ด๋„ ์‘๋‹ต์†๋„๋Š” ๋”œ๋ ˆ์ด๋ฅผ ๋ฌด์‹œํ•˜๊ณ  ๋จผ์ € ์ฒ˜๋ฆฌํ•œ๋‹ค. ์ฝœ๋ฐฑํ•จ์ˆ˜์™€ promise์˜ ์‘๋‹ต์†๋„๊ฐ€ ๊ฑฐ์˜ ๊ฐ™๋‹ค๊ณ  ํ•˜๋Š” ์ด์œ ๋Š”, ๋ธŒ๋ผ์šฐ์ €์˜ ํ™˜๊ฒฝ ์ฐจ์ด๋กœ ์ธํ•ด์„œ ๋ฏธ์„ธํ•œ ์†๋„ ์ฐจ์ด๊ฐ€ ๋ฐœ์ƒ ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ „์ฒด์‘๋‹ต์†๋„๋Š” async/await๋Š” ๋ชจ๋“  ๋น„๋™๊ธฐ์ž‘์—…(setTimeout๊ณผ ๊ฐ™์€ ๋”œ๋ ˆ์ด ์ž‘์—…๋“ค)์ด ๋๋‚˜๊ณ  ์ˆœ์„œ๋Œ€๋กœ ์ฒ˜๋ฆฌ๊ฐ€ ์™„๋ฃŒ ๋œ๋‹ค. ๋”ฐ๋ผ์„œ, ์ฒ˜๋ฆฌ์™„๋ฃŒ๋˜๋Š” ์†๋„๋Š” ๊ฐ€์žฅ ๋А๋ฆฌ๋‹ค๊ณ  ํ•  ์ˆ˜ ์žˆ๋‹ค. **์ฝœ๋ฐฑํ•จ์ˆ˜** ์ฝœ๋ฐฑํ•จ์ˆ˜๋ฅผ ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋จผ์ € 'ํ˜ธ์ด์ŠคํŒ…'์— ๋Œ€ํ•ด ์ดํ•ด ํ•ด์•ผ ํ•œ๋‹ค. **ํ˜ธ์ด์ŠคํŒ…** ํ•จ์ˆ˜ ์•ˆ์— ์žˆ๋Š” ์„ ์–ธ๋“ค์„ ๋ชจ๋‘ ๋Œ์–ด์˜ฌ๋ ค์„œ ํ•ด๋‹น ํ•จ์ˆ˜ ์œ ํšจ๋ฒ”์œ„์˜ ์ตœ์ƒ๋‹จ์— ์„ ์–ธํ•˜๋Š” ๊ฒƒ. *ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋˜๊ธฐ ์ „์— ํ•จ์ˆ˜์— ํ•„์š”ํ•œ ๋ชจ๋“  ๊ฐ’์„ ์ตœ์ƒ๋‹จ์— ์„ ์–ธํ•œ๋‹ค.* **setTimeout(callback , time)** ๋ธŒ๋ผ์šฐ์ € API callback ํ•จ์ˆ˜๋ฅผ time(ms๋‹จ์œ„) ์ดํ›„ ์ถœ๋ ฅํ•œ๋‹ค. **๋™๊ธฐ(Synchronous)์™€ ๋น„๋™๊ธฐ(Asynchronous)** ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” Synchronous ์ด๋‹ค. Synchronous callback ```jsx console.log('1') setTimeout(() => console.log('2'), 1000) console.log('3') function printImmediately(print) { print() } printImmediately(() => console.log('hello')) ``` ํ˜ธ์ด์ŠคํŒ… ๊ฒฐ๊ณผ. ```jsx function printImmediately(print) { // 1. ํ˜ธ์ด์ŠคํŒ… ํ•จ์ˆ˜์„ ์–ธ๋ฌธ print() } console.log('1') // 2. '1' ์ถœ๋ ฅ setTimeout(() => console.log('2'), 1000) // 3. ๋ธŒ๋ผ์šฐ์ €API์— 1์ดˆํ›„์— '2' ์ถœ๋ ฅ ์š”์ฒญ console.log('3') // 4. '3' ์ถœ๋ ฅ printImmediately(() => console.log('hello')) // 5. ํ•จ์ˆ˜ ์ฆ‰์‹œ์ถœ๋ ฅ ์‹คํ–‰ 'hello' ์ถœ๋ ฅ // 6. 1์ดˆ ํ›„, ๋ธŒ๋ผ์šฐ์ €API์— ์˜ํ•ด '2' ์ถœ๋ ฅ ``` Asynchronous callback ```jsx console.log('1') setTimeout(() => console.log('2'), 1000) console.log('3') function printImmediately(print) { print() } printImmediately(() => console.log('hello')) function printWithDelay(print, timeout) { setTimeout(print, timeout) } printWithDelay(() => console.log('async callback'), 2000) ``` ํ˜ธ์ด์ŠคํŒ… ๊ฒฐ๊ณผ ํ˜ธ์ด์ŠคํŒ… ๊ฒฐ๊ณผ ```jsx function printImmediately(print) { print() } function printWithDelay(print, timeout) { setTimeout(print, timeout) } console.log('1') // ๋™๊ธฐ setTimeout(() => console.log('2'), 1000) // ๋น„๋™๊ธฐ------------> console.log('3') // ๋™๊ธฐ printImmediately(() => console.log('hello')) // ๋™๊ธฐ printWithDelay(() => console.log('async callback'), 2000) // ๋น„๋™๊ธฐ -------------> ``` **Promise** Promise๋Š” "๋น„๋™๊ธฐ ์ƒํƒœ๋ฅผ ๊ฐ’์œผ๋กœ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ๋Š” ๊ฐ์ฒด" Promise๊ฐ€ ์™œ ํ•„์š”ํ•œ๊ฐ€์š”? ํ”„๋กœ๋ฏธ์Šค๋Š” ์ฃผ๋กœ ์„œ๋ฒ„์—์„œ ๋ฐ›์•„์˜จ ๋ฐ์ดํ„ฐ๋ฅผ ํ™”๋ฉด์— ํ‘œ์‹œํ•  ๋•Œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ตฌํ˜„ํ•  ๋•Œ ์„œ๋ฒ„์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์š”์ฒญํ•˜๊ณ  ๋ฐ›์•„์˜ค๊ธฐ ์œ„ํ•ด API๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ฝœ๋ฐฑ ํŒจํ„ด์˜ ๋ฌธ์ œ 1. ์ฝœ๋ฐฑ ํ•จ์ˆ˜์˜ ์ค‘์ฒฉ ์‚ฌ์šฉ ```jsx function requestData1(callback) { callback(data) // 2 } function requestData2(callback) { callback(data) // 4 } function onSuccess1(data) { console.log(data) requestData2(onSuccess2) // 3 } function onSuccess2(data) { // 5 console.log(data) } requestData1(onSuccess1) // 1 // ์ฝœ๋ฐฑ ํŒจํ„ด์˜ ์ฝ”๋“œ์˜ ํ๋ฆ„์ด ์ˆœ์ฐจ์ ์ด์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์—, ์ฝ”๋“œ๋ฅผ ์ฝ๊ธฐ๊ฐ€ ํž˜๋“ค๋‹ค. ``` 1. ๊ฐ„๋‹จํ•œ ํ”„๋กœ๋ฏธ์Šค ์ฝ”๋“œ ์˜ˆ ```jsx requestData1() .then((data) => { console.log(data) return requestData2() }) .then((data) => { console.log(data) }) ``` 1. ํ”„๋กœ๋ฏธ์Šค์˜ ์„ธ ๊ฐ€์ง€ ์ƒํƒœ - pending : ๋Œ€๊ธฐ - fulfilled : ์ˆ˜ํ–‰์ด ์ •์ƒ์ ์œผ๋กœ ๋๋‚ฌ๊ณ  ๊ฒฐ๊ณผ๊ฐ’ ์กด์žฌ - rejected : ์ˆ˜ํ–‰์ด ๋น„์ •์ƒ์ ์œผ๋กœ ๋๋‚ฌ์Œ. - settled : ์ดํ–‰๋จ , ๊ฑฐ๋ถ€๋จ ์ƒํƒœ ํ”„๋กœ๋ฏธ์Šค๋Š” ์ฒ˜๋ฆฌ ๋จ ์ƒํƒœ๊ฐ€ ๋˜๋ฉด ๋” ์ด์ƒ ๋‹ค๋ฅธ ์ƒํƒœ๋กœ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๋Š”๋‹ค. ๋Œ€๊ธฐ ์ค‘ ์ƒํƒœ์ผ ๋•Œ๋งŒ ์ดํ–‰๋จ ๋˜๋Š” ๊ฑฐ๋ถ€๋จ ์ƒํƒœ๋กœ ๋ณ€ํ•  ์ˆ˜ ์žˆ๋‹ค. 2. ํ”„๋กœ๋ฏธ์Šค๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ• ```js const p1 = new Promise((resolve, reject) => { resolve(data) // or reject('error message') }) const p2 = Promise.reject('error message') const p3 = Promise.resolve(param) ``` 3. Promise.resolve ๋ฐ˜ํ™˜ ๊ฐ’ ```js const p1 = Promise.resolve(123) console.log(p1 !== 123) // true ์ดํ–‰๋จ ์ƒํƒœ์ธ ํ”„๋กœ๋ฏธ์Šค๊ฐ€ ๋ฐ˜ํ™˜๋œ๋‹ค. const p2 = new Promise((resolve) => setTimeout(() => resolve(10), 1)) console.log(Promise.resolve(p2) === p2) // true // Promise.resolve ํ•จ์ˆ˜์— ํ”„๋กœ๋ฏธ์Šค๊ฐ€ ์ž…๋ ฅ๋˜๋ฉด ๊ทธ ์ž์‹ ์ด ๋ฐ˜ํ™˜๋œ๋‹ค. ``` 4. ํ”„๋กœ๋ฏธ์Šค ์ด์šฉํ•˜๊ธฐ .then then์€ ์ฒ˜๋ฆฌ ๋จ ์ƒํƒœ๊ฐ€ ๋œ ํ”„๋กœ๋ฏธ์Šค ์ฒ˜๋ฆฌ ํ•  ๋•Œ ์‚ฌ์šฉ๋˜๋Š” ๋ฉ”์„œ๋“œ. ```js //requestData().then(onResolve, onReject); // ํ”„๋กœ๋ฏธ์Šค ์ฒ˜๋ฆฌ๋จ ์ƒํƒœ๊ฐ€ ๋˜๋ฉด, onResolve ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜๊ณ , ๊ฑฐ๋ถ€๋จ ์ƒํƒœ๊ฐ€ ๋˜๋ฉด onReject ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ ๋œ๋‹ค. Promise.resolve(123).then((data) => console.log(data)) // 123 Promise.reject('err').then(null, (error) => console.log(error)) // err ``` 5. ์—ฐ์†ํ•ด์„œ then ๋ฉ”์„œ๋“œ ํ˜ธ์ถœํ•˜๊ธฐ ```js let requestData1 = new Promise((resolve, reject) => { setTimeout(() => { resolve('hun') }, 1000) }) let requestData2 = new Promise((resolve, reject) => { setTimeout(() => { resolve('jenny') }, 2000) }) requestData1 .then((data) => { console.log(data) return requestData2 // 1 }) .then((data) => { return data + 1 // 2 }) .then((data) => { throw new Error('some Error') // 3 }) .then(null, (error) => { console.log(error) }) ``` 1. ํ•จ์ˆ˜์—์„œ ํ”„๋กœ๋ฏธ์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉด then๋ฉ”์„œ๋“œ๋Š” ๊ทธ ๊ฐ’์„ ๊ทธ๋Œ€๋กœ ๋ฐ˜ํ™˜ํ•œ๋‹ค. 2. ํ”„๋กœ๋ฏธ์Šค๊ฐ€ ์•„๋‹Œ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋ฉด, then ๋ฉ”์„œ๋“œ๋Š” ์ดํ–‰๋จ ์ƒํƒœ์ธ ํ”„๋กœ๋ฏธ์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. 3. ํ•จ์ˆ˜ ๋‚ด๋ถ€์—์„œ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด then ๋ฉ”์„œ๋“œ๋Š” ๊ฑฐ๋ถ€๋จ ์ƒํƒœ์ธ ํ”„๋กœ๋ฏธ์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. 4. ๊ฑฐ๋ถ€๋จ ์ƒํƒœ๊ฐ€ ๋˜๋ฉด onReject ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค. ```js Promise.reject('err') .then(() => console.log('then 1')) // 1๋ฒˆ .then(() => console.log('then 2')) // 1๋ฒˆ .then( () => console.log('then 3'), () => console.log('then 4') ) // 2๋ฒˆ .then( () => console.log('then 5'), () => console.log('then 6') ) // 3๋ฒˆ ``` ๊ฑฐ๋ถ€ ๋จ ์ƒํƒœ์ธ ํ”„๋กœ๋ฏธ์Šค๋Š” ์ฒ˜์Œ์œผ๋กœ ๋งŒ๋‚˜๋Š” onReject ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœ ํ•˜๋ฏ€๋กœ 1๋ฒˆ ์ด ์ƒ๋žต๋˜๊ณ , 2๋ฒˆ ์ฝ”๋“œ์˜ then 4๊ฐ€ ์ถœ๋ ฅ ๋œ๋‹ค. then 4๋ฅผ ์ถœ๋ ฅํ•˜๋Š” ํ•จ์ˆ˜๋Š” undefined ๋ฅผ ๊ฒฐ๊ณผ๋กœ ๊ฐ€์ง€๋ฉด์„œ ์ดํ–‰๋จ ์ƒํƒœ์ธ ํ”„๋กœ๋ฏธ์Šค๋ฅผ ์ƒ์„ฑํ•œ๋‹ค. 3๋ฒˆ ๋”ฐ๋ผ์„œ ์ด์–ด์ง€๋Š” then ๋ฉ”์„œ๋“œ์—์„œ๋Š” then 5๊ฐ€ ์ถœ๋ ฅ๋œ๋‹ค. then ๋ฉ”์„œ๋“œ์˜ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ํŠน์ง•์€ ํ•ญ์ƒ ์—ฐ๊ฒฐ๋œ ์ˆœ์„œ๋Œ€๋กœ ํ˜ธ์ถœ๋œ๋‹ค๋Š” ์ ์ด๋‹ค. 6. ํ”„๋กœ๋ฏธ์Šค ์ด์šฉํ•˜๊ธฐ 2 : catch catch๋Š” ํ”„๋กœ๋ฏธ์Šค ์ˆ˜ํ–‰ ์ค‘ ๋ฐœ์ƒํ•œ ์˜ˆ์™ธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฉ”์„œ๋“œ์ด๋‹ค. catch๋ฉ”์„œ๋“œ๋Š” then ๋ฉ”์„œ๋“œ์˜ onReject ํ•จ์ˆ˜์™€ ๊ฐ™์€ ์—ญํ• ์„ ํ•œ๋‹ค. ```js Promise.reject(1).then(null, (error) => { console.log(error) }) Promise.reject(1).catch((error) => { console.log(error) }) ``` ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๋Š” then๋ฉ”์„œ๋“œ์˜ onReject๋ฅผ ์ด์šฉํ•˜๊ธฐ๋ณด๋‹ค๋Š”, catch๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•˜๋Š”๊ฒŒ ๊ฐ€๋…์„ฑ ๋ฉด์—์„œ ์ข‹๋‹ค. 7. then ๋ฉ”์„œ๋“œ์˜ onReject๋ฅผ ์‚ฌ์šฉํ–ˆ์„ ๋•Œ ๋ฌธ์ œ์ . ```js Promise.resolve().then( () => { // 1๋ฒˆ throw new Error('some error') }, (error) => { // 2๋ฒˆ console.log(error) } ) ``` 1๋ฒˆ then ๋ฉ”์„œ๋“œ์˜ resolve ํ•จ์ˆ˜์—์„œ ๋ฐœ์ƒํ•œ ์˜ˆ์™ธ๋Š” ๊ฐ™์€ then ๋ฉ”์„œ๋“œ์˜ 2๋ฒˆ rejectํ•จ์ˆ˜์—์„œ ์ฒ˜๋ฆฌ๋˜์ง€ ์•Š๋Š”๋‹ค. ์‹คํ–‰ํ•˜๋ฉด Unhandled promise rejection ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. ๊ฑฐ๋ถ€๋จ ์ƒํƒœ์ธ ํ”„๋กœ๋ฏธ์Šค๋ฅผ ์ฒ˜๋ฆฌํ•˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. 8. onReject ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  catch๋ฅผ ์‚ฌ์šฉํ•œ ์˜ˆ ```js Promise.resolve() .then(() => { throw new Error('some error') }) .catch((error) => { console.log(error) }) ``` 9. catch ๋ฉ”์„œ๋“œ ์ดํ›„์—๋„ then ๋ฉ”์„œ๋“œ ์‚ฌ์šฉํ•˜๊ธฐ ```js Promise.reject(10) .then((data) => { console.log('then1:', data) return 20 }) .catch((error) => { console.log('catch:', error) return 30 }) .then((data) => { console.log('then2:', data) }) // catch: 10 // then2: 30 ``` ํ”„๋กœ๋ฏธ์Šค ์ด์šฉํ•˜๊ธฐ 3 : finally - finally๋ฅผ ์‚ฌ์šฉํ•œ ๊ฐ„๋‹จํ•œ ์ฝ”๋“œ ```js requestData() .then(data => { ... }) .catch(error => { ... }) .finally(() => { ... }); ``` - finally ๋ฉ”์„œ๋“œ๋Š” ์ƒˆ๋กœ์šด ํ”„๋กœ๋ฏธ์Šค๋ฅผ ์ƒ์„ฑํ•˜์ง€ ์•Š๋Š”๋‹ค. ```js function requestData(){ return fetch() .catch(error => { ... }) .finally(() => { senLogToServer('requestData finished') }) } requestData().then(data => console.log(data)); // 1๋ฒˆ ``` 1๋ฒˆ, requestData ํ•จ์ˆ˜์˜ ๋ฐ˜ํ™˜๊ฐ’์€ finally ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ์ด์ „์˜ ํ”„๋กœ๋ฏธ์Šค๋‹ค. ๋”ฐ๋ผ์„œ, requestDataํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ž…์žฅ์—์„œ๋Š” finally ๋ฉ”์„œ๋“œ ์กด์žฌ ์—ฌ๋ถ€๋ฅผ ์‹ ๊ฒฝ ์“ฐ์ง€ ์•Š์•„๋„ ๋œ๋‹ค. **ํ”„๋กœ๋ฏธ์Šค ํ™œ์šฉํ•˜๊ธฐ** **๋ณ‘๋ ฌ๋กœ ์ฒ˜๋ฆฌํ•˜๊ธฐ : Promise.all** Promise.all์€ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ํ”„๋กœ๋ฏธ์Šค๋ฅผ ๋ณ‘๋ ฌ๋กœ ์ฒ˜๋ฆฌํ•  ๋•Œ ์‚ฌ์šฉ๋˜๋Š” ํ•จ์ˆ˜์ด๋‹ค. then ๋ฉ”์„œ๋“œ๋ฅผ ์ฒด์ธ์œผ๋กœ ์—ฐ๊ฒฐํ•˜๋ฉด ๊ฐ๊ฐ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๊ฐ€ ๋ณ‘๋ ฌ๋กœ ์ฒ˜๋ฆฌ๋˜์ง€ ์•Š๋Š” ๋‹จ์ ์„ ๊ทน๋ณตํ•œ๋‹ค. - ์ˆœ์ฐจ์ ์œผ๋กœ ์‹คํ–‰๋˜๋Š” ๋น„๋™๊ธฐ ์ฝ”๋“œ ```js requestData1() .then((data) => { console.log(data) return requestData2() }) .then((data) => { console.log(data) }) ``` ๋น„๋™๊ธฐ ํ•จ์ˆ˜ ๊ฐ„์— ์„œ๋กœ ์˜์กด์„ฑ์ด ์—†๋‹ค๋ฉด, ๋ณ‘๋ ฌ๋กœ ์ฒ˜๋ฆฌํ•˜๋Š”๊ฒŒ ๋” ๋น ๋ฅด๋‹ค. then ๋ฉ”์„œ๋“œ๋ฅผ ์ฒด์ธ์œผ๋กœ ์—ฐ๊ฒฐํ•˜์ง€ ์•Š๊ณ , ๋น„๋™๊ธฐํ•จ์ˆ˜๋ฅผ ๊ฐ๊ฐ ํ˜ธ์ถœํ•˜๋ฉด, ๋ณ‘๋ ฌ๋กœ ์ฒ˜๋ฆฌ ๋œ๋‹ค. - ๋ณ‘๋ ฌ๋กœ ์‹คํ–‰ ๋˜๋Š” ์ฝ”๋“œ ```js requestData1().then((data) => { console.log(data) }) requestData2().then((data) => { console.log(data) }) ``` requestData1๊ณผ requestData2๋Š” ๋™์‹œ์— ์‹คํ–‰ ๋œ๋‹ค. ์—ฌ๋Ÿฌ ํ”„๋กœ๋ฏธ์Šค๋ฅผ ๋ณ‘๋ ฌ๋กœ ์ฒ˜๋ฆฌํ•˜๊ณ  ์‹ถ์„ ๊ฒฝ์šฐ Promise.all์„ ์‚ฌ์šฉํ•˜์ž. - Promise.all ์„ ์‚ฌ์šฉํ•˜๋Š” ์ฝ”๋“œ ```js Promise.all([requestData1(), requestData2()]).then(([data1, data2]) => { console.log(data1, data2) }) ``` Promise.all ํ•จ์ˆ˜๋Š” ํ”„๋กœ๋ฏธ์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. Promise.all ํ•จ์ˆ˜๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ”„๋กœ๋ฏธ์Šค๋Š” ์ž…๋ ฅ๋œ ๋ชจ๋“  ํ”„๋กœ๋ฏธ์Šค๊ฐ€ ์ฒ˜๋ฆฌ๋จ ์ƒํƒœ๊ฐ€ ๋˜์–ด์•ผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์ฒ˜๋ฆฌ๋จ ์ƒํƒœ๊ฐ€ ๋œ๋‹ค. ๋งŒ์•ฝ ํ•˜๋‚˜๊ฐ€ ๊ฑฐ๋ถ€๋จ ์ƒํƒœ๊ฐ€ ๋œ๋‹ค๋ฉด, Promise.all ํ•จ์ˆ˜๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ”„๋กœ๋ฏธ์Šค๋„ ๊ฑฐ๋ถ€๋จ ์ƒํƒœ๊ฐ€ ๋œ๋‹ค. **๊ฐ€์žฅ ๋นจ๋ฆฌ ์ฒ˜๋ฆฌ๋œ ํ”„๋กœ๋ฏธ์Šค ๊ฐ€์ ธ์˜ค๊ธฐ : Promise.race** Promise.race ํ•จ์ˆ˜์— ์ž…๋ ฅ๋œ ์—ฌ๋Ÿฌ ํ”„๋กœ๋ฏธ์Šค ์ค‘์—์„œ ํ•˜๋‚˜๋ผ๋„ ์ฒ˜๋ฆฌ๋จ ์ƒํƒœ๊ฐ€ ๋˜๋ฉด, Promise.race ํ•จ์ˆ˜๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ”„๋กœ๋ฏธ์Šค๋„ ์ฒ˜๋ฆฌ๋จ ์ƒํƒœ๊ฐ€ ๋œ๋‹ค. - Promise.race๋ฅผ ์‚ฌ์šฉํ•œ ๊ฐ„๋‹จํ•œ ์ฝ”๋“œ ```js Promise.race([ requestData(), new Promise((_, reject) => setTimeout(reject, 3000)), ]) .then((data) => console.log(data)) .catch((error) => console.log(error)) ``` requestData ํ•จ์ˆ˜๊ฐ€ 3์ดˆ์•ˆ์— ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์œผ๋ฉด then๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜๊ณ  ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด catch ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ ๋œ๋‹ค. **ํ”„๋กœ๋ฏธ์Šค๋ฅผ ์ด์šฉํ•œ ๋ฐ์ดํ„ฐ ์บ์‹ฑ** ์ฒ˜๋ฆฌ๋จ ์ƒํƒœ๊ฐ€ ๋˜๋ฉด, ๊ทธ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜๋Š” ํ”„๋กœ๋ฏธ์Šค์˜ ์„ฑ์งˆ์„ ์ด์šฉํ•ด์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์บ์‹ฑํ•  ์ˆ˜ ์žˆ๋‹ค. - ํ”„๋กœ๋ฏธ์Šค๋กœ ์บ์‹ฑ ๊ธฐ๋Šฅ ๊ตฌํ˜„ํ•˜๊ธฐ. ```js let cachedPromise function getData() { cachedPromise = cachedPromise || requestData() // 1๋ฒˆ return cachedPromise } getData().then((v) => console.log(v)) getData().then((v) => console.log(v)) ``` 1๋ฒˆ getData ํ•จ์ˆ˜๋ฅผ ์ฒ˜์Œ ํ˜ธ์ถœ ํ•  ๋•Œ๋งŒ, requestData๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค. ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ์ž‘์—…์ด ๋๋‚˜๋ฉด, ๊ทธ ๊ฒฐ๊ณผ๋Š” cachedPromise ํ”„๋กœ๋ฏธ์Šค์— ์ €์žฅ๋œ๋‹ค. **ํ”„๋กœ๋ฏธ์Šค ์‚ฌ์šฉ ์‹œ ์ฃผ์˜ ํ•  ์ ** - return ํ‚ค์›Œ๋“œ ๊นœ๋นกํ•˜์ง€ ์•Š๊ธฐ. then ๋ฉ”์„œ๋“œ ๋‚ด๋ถ€ ํ•จ์ˆ˜์—์„œ return ํ‚ค์›Œ๋“œ๋ฅผ ์ž…๋ ฅํ•˜๋Š” ๊ฒƒ์„ ๊นœ๋นกํ•˜๊ธฐ ์‰ฝ๋‹ค. then ๋ฉ”์„œ๋“œ๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ”„๋กœ๋ฏธ์Šค ๊ฐ์ฒด์˜ ๋ฐ์ดํ„ฐ๋Š” ๋‚ด๋ถ€ํ•จ์ˆ˜๊ฐ€ ๋ฐ˜ํ™˜ํ•œ ๊ฐ’์ด๋‹ค. return ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ฉด ํ”„๋กœ๋ฏธ์Šค ๊ฐ์ฒด์˜ ๋ฐ์ดํ„ฐ๋Š” undefined๊ฐ€ ๋œ๋‹ค. - return ํ‚ค์›Œ๋“œ๋ฅผ ๊นœ๋นกํ•œ ์ฝ”๋“œ ```js Promise.resolve(10) .then((data) => { console.log(data) Promise.resolve(20) // 2๋ฒˆ }) .then((data) => { console.log(data) // 1๋ฒˆ }) ``` 1๋ฒˆ์€ ์˜๋„์™€๋Š” ๋‹ค๋ฅด๊ฒŒ undefined๊ฐ€ ์ถœ๋ ฅ ๋œ๋‹ค. 2๋ฒˆ ์ฝ”๋“œ์—์„œ return ํ‚ค์›Œ๋“œ๋ฅผ ์ž…๋ ฅํ•˜๋ฉด ์˜๋„ํ•œ ๋Œ€๋กœ 20์ด ์ถœ๋ ฅ ๋œ๋‹ค. - ํ”„๋กœ๋ฏธ์Šค๋Š” ๋ถˆ๋ณ€ ๊ฐ์ฒด๋ผ๋Š” ์‚ฌ์‹ค ๋ช…์‹ฌํ•˜๊ธฐ ํ”„๋กœ๋ฏธ์Šค๋Š” ๋ถˆ๋ณ€ ๊ฐ์ฒด์ด๋‹ค. - ํ”„๋กœ๋ฏธ์Šค๊ฐ€ ์ˆ˜์ •๋œ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๊ณ  ์ž‘์„ฑํ•œ ์ฝ”๋“œ ```js function requestData() { const p = Promise.resolve(10) p.then(() => { // 1๋ฒˆ return 20 }) return p } requestData().then((v) => { console.log(v) // 10 // 2๋ฒˆ }) ``` 1๋ฒˆ then ๋ฉ”์„œ๋“œ๋Š” ๊ธฐ์กด ๊ฐ์ฒด๋ฅผ ์ˆ˜์ •ํ•˜์ง€ ์•Š๊ณ , ์ƒˆ๋กœ์šด ํ”„๋กœ๋ฏธ์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. 2๋ฒˆ, ์ฝ”๋“œ์—์„œ 20์ด ์ถœ๋ ฅ๋˜๊ธธ ์›ํ•œ๋‹ค๋ฉด requestData ํ•จ์ˆ˜๋ฅผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ˆ˜์ •ํ•ด์•ผ ํ•œ๋‹ค. - then ๋ฉ”์„œ๋“œ๋กœ ์ƒ์„ฑ๋œ ํ”„๋กœ๋ฏธ์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ฝ”๋“œ. ```js function requestData() { return Promise.resolve(10).then((v) => { return 20 }) } ``` - ํ”„๋กœ๋ฏธ์Šค๋ฅผ ์ค‘์ฒฉํ•ด์„œ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ธฐ ํ”„๋กœ๋ฏธ์Šค๋ฅผ ์ค‘์ฒฉํ•ด์„œ ์‚ฌ์šฉํ•˜๋ฉด ์ฝœ๋ฐฑ ํ—ฌ๊ณผ๊ฐ™์ด ํ”„๋กœ๋ฏธ์Šค ํ—ฌ์ด ๋ฐœ์ƒํ•œ๋‹ค. ```js requestData1().then(result1 => { requestData2(result2 => { .... }); }); ``` ๊ฐ€๋…์„ฑ์ด ์ข‹์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์—, ์•„๋ž˜ 24๋ฒˆ๊ณผ ๊ฐ™์ด ๋ฐ”๊พธ์ž. - ์ค‘์ฒฉ๋œ ์ฝ”๋“œ๋ฅผ ๋ฆฌํŒฉํ„ฐ๋ง ํ•œ ์ฝ”๋“œ ```js requestData1() .then(result1 => { return requestData2(result1) }) .then(result2 => { return ... // 1๋ฒˆ }) ``` ๋งŒ์•ฝ 1๋ฒˆ, ์—์„œ result1 ๋ณ€์ˆ˜๋ฅผ ์ฐธ์กฐ ํ•ด์•ผ ํ•œ๋‹ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ• ๊นŒ? - Promise.all ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ”„๋กœ๋ฏธ์Šค๋ฅผ ์ค‘์ฒฉํ•˜์ง€ ์•Š๊ณ ๋„ ํ•ด๊ฒฐํ• ์ˆ˜ ์žˆ๋‹ค. - Promise.all์„ ์‚ฌ์šฉํ•ด์„œ ๋ณ€์ˆ˜ ์ฐธ์กฐ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•œ ์ฝ”๋“œ ```js requestData1() .then(result1 => { return Promise.all([result1, requestData2(result1)]) // 1๋ฒˆ .then(([result1, result2]) => { ........... }); ``` 1๋ฒˆ, Promise.all ํ•จ์ˆ˜๋กœ ์ž…๋ ฅํ•˜๋Š” ๋ฐฐ์—ด์— ํ”„๋กœ๋ฏธ์Šค๊ฐ€ ์•„๋‹Œ ๊ฐ’์„ ๋„ฃ์œผ๋ฉด, ๊ทธ ๊ฐ’์„ ๊ทธ๋Œ€๋กœ ์ดํ–‰๋จ ์ƒํƒœ์ธ ํ”„๋กœ๋ฏธ์Šค์ฒ˜๋Ÿผ ์ฒ˜๋ฆฌ๋œ๋‹ค. **๋™๊ธฐ ์ฝ”๋“œ์˜ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ์‹ ๊ฒฝ ์“ฐ๊ธฐ** ํ”„๋กœ๋ฏธ์Šค๋ฅผ ๋™๊ธฐ(sync)์ฝ”๋“œ์™€ ๊ฐ™์ด ์‚ฌ์šฉํ•  ๋•Œ๋Š” ์˜ˆ์™ธ ์ฒ˜๋ฆฌ์— ์‹ ๊ฒฝ ์จ์•ผ ํ•œ๋‹ค. - ๋™๊ธฐ ์ฝ”๋“œ์—์„œ ๋ฐœ์ƒํ•œ ์˜ˆ์™ธ๊ฐ€ ์ฒ˜๋ฆฌ๋˜์ง€ ์•Š๋Š” ์ฝ”๋“œ. ```js function requestData() { doSync() // 1๋ฒˆ return fetch() .then((data) => console.log(data)) .catch((error) => console.log(error)) } ``` 1๋ฒˆ, doSync ํ•จ์ˆ˜๊ฐ€ ๋ฐ˜๋“œ์‹œ fetch ์ „์— ํ˜ธ์ถœ๋˜์–ด์•ผ ํ•˜๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด then ๋ฉ”์„œ๋“œ ์•ˆ์— ๋„ฃ์–ด์ฃผ๋Š”๊ฒŒ ์ข‹๋‹ค. - ๋™๊ธฐ ์ฝ”๋“œ๋„ ์˜ˆ์™ธ์ฒ˜๋ฆฌ๊ฐ€ ๋˜๋Š” ์ฝ”๋“œ ```js function requestData() { return fetch() .then((data) => { doSync() console.log(data) }) .catch((error) => console.log(Error)) } ``` doSync์—์„œ ๋ฐœ์ƒํ•˜๋Š” ์˜ˆ์™ธ๋Š” catch ๋ฉ”์„œ๋“œ์—์„œ ์ฒ˜๋ฆฌ๊ฐ€ ๋œ๋‹ค. **ํ–ฅ์ƒ๋œ ๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ async, await** async await ์ดํ•ดํ•˜๊ธฐ ํ”„๋กœ๋ฏธ์Šค๋Š” ๊ฐ์ฒด๋กœ ์กด์žฌํ•˜์ง€๋งŒ, async await๋Š” ํ•จ์ˆ˜์— ์ ์šฉ๋˜๋Š” ๊ฐœ๋…์ด๋‹ค. ํ”„๋กœ๋ฏธ์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” async await ํ•จ์ˆ˜ ```js async function getData() { return 123 //Promise {<fulfilled>: 123} } getData().then((data) => console.log(data)) // 123 Promise {<fulfilled>: undefined} ``` - ํ”„๋กœ๋ฏธ์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” async await ํ•จ์ˆ˜ ```js async function getData() { return Promise.resolve(123) } getData().then((data) => console.log(data)) ``` ํ”„๋กœ๋ฏธ์Šค์˜ then ๋ฉ”์„œ๋“œ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ async await ํ•จ์ˆ˜ ๋‚ด๋ถ€์—์„œ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฐ’์ด ํ”„๋กœ๋ฏธ์Šค๋ผ๋ฉด ๊ทธ ๊ฐ์ฒด๋ฅผ ๊ทธ๋Œ€๋กœ ๋ฐ˜ํ™˜ํ•œ๋‹ค. - async await ํ•จ์ˆ˜์—์„œ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ฒฝ์šฐ. ```js async function getData() { throw new Error('123') } getData().catch((error) => console.log(error)) // Error : 123 ``` - await ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ• ```js function requestData(value) { return new Promise((resolve) => setTimeout(() => { console.log('requestData:', value) resolve(value) }, 100) ) } async function getData() { const data1 = await requestData(10) //1๋ฒˆ const data2 = await requestData(20) //1๋ฒˆ console.log(data1, data2) // 2๋ฒˆ return [data1, data2] } getData() // requestData: 10 // 3๋ฒˆ // requestData: 20 // 3๋ฒˆ // 10, 20 // 3๋ฒˆ ``` 1๋ฒˆ, requestData ํ•จ์ˆ˜๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ”„๋กœ๋ฏธ์Šค๊ฐ€ ์ฒ˜๋ฆฌ๋จ ์ƒํƒœ๊ฐ€ ๋  ๋•Œ ๊นŒ์ง€ 2๋ฒˆ,์˜ ์ฝ”๋“œ๋Š” ์‹คํ–‰๋˜์ง€ ์•Š๋Š”๋‹ค. ๋”ฐ๋ผ์„œ getData ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœ ํ•œ ๊ฒฐ๊ณผ๋Š” 3๋ฒˆ,์ด๋‹ค. async ํ‚ค์›Œ๋“œ๋Š” ์˜ค์ง async await ํ•จ์ˆ˜ ๋‚ด์—์„œ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์ผ๋ฐ˜ํ•จ์ˆ˜์—์„œ ์‚ฌ์šฉํ•˜๋ฉด ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. - await ํ‚ค์›Œ๋“œ๋Š” async ํ‚ค์›Œ๋“œ ์—†์ด ์‚ฌ์šฉ ํ•  ์ˆ˜ ์—†๋‹ค. ```js function getData(){ const data = await requestData(10); // ์—๋Ÿฌ ๋ฐœ์ƒ console.log(data); } ``` **async await๋Š” ํ”„๋กœ๋ฏธ์Šค๋ณด๋‹ค ๊ฐ€๋…์„ฑ์ด ์ข‹๋‹ค.** - async await์™€ ํ”„๋กœ๋ฏธ์Šค ๋น„๊ตํ•˜๊ธฐ ```js function getDataPromise() { asyncFunc1() .then((data) => { console.log(data) return asyncFunc2() }) .then((data) => { console.log(data) }) } // 1๋ฒˆ ํ”„๋กœ๋ฏธ์Šค๋กœ ์ž‘์„ฑํ•œ ์ฝ”๋“œ async function getDataAsync() { const data1 = await asyncFunc1() console.log(data1) const data2 = await asyncFunc2() console.log(data2) } // 2๋ฒˆ async await๋กœ ์ž‘์„ฑํ•œ ์ฝ”๋“œ ``` ๊ฐ€๋…์„ฑ์ด async await๋กœ ์ž‘์„ฑ ํ•œ ์ฝ”๋“œ๊ฐ€ ์ข‹๋‹ค. ๊ฐ„๊ฒฐํ•œ ์ด์œ ๋Š” async await ํ•จ์ˆ˜๋Š” then ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ํ•„์š”๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. - ์˜์กด์„ฑ์ด ๋†’์€ ์ฝ”๋“œ์—์„œ ๊ฐ€๋…์„ฑ ๋น„๊ตํ•˜๊ธฐ ```js function getDataPromise() { return asyncFunc1() .then(data1 => Promise.all([data1, asyncFunc2(data1)])) // 1๋ฒˆ .then([data1, data2]) => { return asyncFunc3(data1,data2); }); } async function getDataAsync() { // 2๋ฒˆ const1 data1 = await asyncFunc1(); const2 data2 = await asyncFunc2(data1); return asyncFunc3(data1, data2); } ``` 1๋ฒˆ, ๋‘ ๋ฐ˜ํ™˜๊ฐ’์„ asyncFunc3 ํ•จ์ˆ˜์— ์ „๋‹ฌํ•˜๊ธฐ ์œ„ํ•ด Promise.all์„ ์‚ฌ์šฉํ–ˆ๋‹ค. 2๋ฒˆ, async awaitํ•จ์ˆ˜๋Š” ๋ณต์žกํ•œ ์˜์กด์„ฑ์ด ์กด์žฌํ•จ์—๋„ ์ฝ”๋“œ๊ฐ€ ์ง๊ด€์ ์ด๋‹ค. **async await ํ™œ์šฉํ•˜๊ธฐ** - ๋น„๋™๊ธฐ ํ•จ์ˆ˜๋ฅผ ๋ณ‘๋ ฌ๋กœ ์‹คํ–‰ํ•˜๊ธฐ. * ์ˆœ์ฐจ์ ์œผ๋กœ ์‹คํ–‰๋˜๋Š” ๋น„๋™๊ธฐ ์ฝ”๋“œ ```js async function getData() { const data1 = await asyncFunc1() const data2 = await asyncFunc2() // ... } ``` ๋‘ ํ•จ์ˆ˜์‚ฌ์ด์— ์˜์กด์„ฑ์ด ์—†๋‹ค๋ฉด, ๋™์‹œ์— ์‹คํ–‰ํ•˜๋Š”๊ฒŒ ๋” ์ข‹๋‹ค. ํ”„๋กœ๋ฏธ์Šค๋Š” ์ƒ์„ฑ๊ณผ ๋™์‹œ์— ๋น„๋™๊ธฐ ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋œ๋‹ค. ๋”ฐ๋ผ์„œ, ๋‘ ๊ฐœ์˜ ํ”„๋กœ๋ฏธ์Šค๋ฅผ ๋จผ์ € ์ƒ์„ฑํ•˜๊ณ  await ํ‚ค์›Œ๋“œ๋ฅผ ๋‚˜์ค‘์— ์‚ฌ์šฉํ•˜๋ฉด ๋ณ‘๋ ฌ๋กœ ์‹คํ–‰๋˜๋Š” ์ฝ”๋“œ๊ฐ€ ๋œ๋‹ค. - await ํ‚ค์›Œ๋“œ๋ฅผ ๋‚˜์ค‘์— ์‚ฌ์šฉํ•ด์„œ ๋ณ‘๋ ฌ๋กœ ์‹คํ–‰๋˜๋Š” ๋น„๋™๊ธฐ ์ฝ”๋“œ ```js async function getData() { const p1 = asyncFunc1() const p2 = asyncFunc2() const data1 = await p1 const data2 = await p2 } ``` - Promise.all์„ ์‚ฌ์šฉํ•ด์„œ ๋ณ‘๋ ฌ๋กœ ์ฒ˜๋ฆฌํ•˜๊ธฐ ```js async function getData() { const [data1, data2] = await Promise.all([asyncFunc1(), asyncFunc2()]) // .... } ``` - ์˜ˆ์™ธ ์ฒ˜๋ฆฌํ•˜๊ธฐ async await ํ•จ์ˆ˜ ๋‚ด๋ถ€์—์„œ ๋ฐœ์ƒํ•˜๋Š” ์˜ˆ์™ธ๋Š” try catch ๋ฌธ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋Š”๊ฒŒ ์ข‹๋‹ค. - ๋™๊ธฐ์™€ ๋น„๋™๊ธฐ ํ•จ์ˆ˜ ๋ชจ๋‘ catch ๋ฌธ์—์„œ ์ฒ˜๋ฆฌ๋œ๋‹ค. ```js async function getData() { try { await doAsync() return doSync() } catch (error) { console.log(error) } } ``` ๋น„๋™๊ธฐํ•จ์ˆ˜์™€ ๋™๊ธฐํ•จ์ˆ˜์—์„œ ๋ฐœ์ƒํ•˜๋Š” ๋ชจ๋“  ์˜ˆ์™ธ๊ฐ€ catch๋ฌธ์—์„œ ์ฒ˜๋ฆฌ๋œ๋‹ค. - Thenable์„ ์ง€์›ํ•˜๋Š” async await Thenable์€ ํ”„๋กœ๋ฏธ์Šค ์ฒ˜๋Ÿผ ๋™์ž‘ํ•˜๋Š” ๊ฐ์ฒด๋‹ค. - async await ํ•จ์ˆ˜์—์„œ Thenable์„ ์‚ฌ์šฉํ•œ ์˜ˆ ```js class ThenableExample { then(resolve, reject) { // 1๋ฒˆ setTimeout(() => resolve(123), 1000) } } async function asyncFunc() { const result = await new ThenableExaple() // 2๋ฒˆ console.log(result) // 123 } ``` 1๋ฒˆ ThenableExample ํด๋ž˜์Šค๋Š” then ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฏ€๋กœ, ThenableExample ํด๋ž˜์Šค๋กœ ์ƒ์„ฑ๋œ ๊ฐ์ฒด๋Š” Thenable์ด๋‹ค. 2๋ฒˆ async await ํ•จ์ˆ˜๋Š” Thenable๋„ ํ”„๋กœ๋ฏธ์Šค ์ฒ˜๋Ÿผ ์ฒ˜๋ฆฌํ•œ๋‹ค. - sync/await , promise ์ฐจ์ด promise : ์ฝ”๋“œ ์‹คํ–‰ ์ค‘์— ๋งŒ๋‚˜๋”๋ผ๋„ ๋ฌด์‹œํ•˜๊ณ  ๋‹ค์Œ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•œ๋‹ค. async-await : await์„ ๋งŒ๋‚ฌ์„ ๋•Œ ,ํ•ด๋‹น ์ฝ”๋“œ๊ฐ€ ๋๋‚ ๋•Œ๊นŒ์ง€(์š”์ฒญ์ด ๋งˆ๋ฌด๋ฆฌ ๋  ๋–„๊นŒ์ง€, pending์ด ์•„๋‹๋–„๊นŒ์ง€) ๊ธฐ๋‹ค๋ ธ๋‹ค ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.