'for await...of' ๋ฃจํ์ ์ฌ์ฉ์ ์ ์ ๋น๋๊ธฐ ์ดํฐ๋ ์ดํฐ ํฌํผ๋ฅผ ์ฌ์ฉํ์ฌ ์๋ฐ์คํฌ๋ฆฝํธ์ ๋น๋๊ธฐ ๋ฐ๋ณต์ ๋ง์คํฐํ์ธ์. ์ค์ ์์ ๋ฅผ ํตํด ์คํธ๋ฆผ ์ฒ๋ฆฌ์ ๋ฐ์ดํฐ ํธ๋ค๋ง์ ํฅ์์ํฌ ์ ์์ต๋๋ค.
์๋ฐ์คํฌ๋ฆฝํธ ๋น๋๊ธฐ ์ดํฐ๋ ์ดํฐ ํฌํผ: For Each - ์คํธ๋ฆผ ์ฒ๋ฆฌ ๋ฐ๋ณต
๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ์ ์ต์ ์๋ฐ์คํฌ๋ฆฝํธ ๊ฐ๋ฐ์ ํต์ฌ์ผ๋ก, ๋ฉ์ธ ์ค๋ ๋๋ฅผ ์ฐจ๋จํ์ง ์๊ณ ์๊ฐ์ด ๋ง์ด ๊ฑธ๋ฆฌ๋ ์์ ์ ์ ํ๋ฆฌ์ผ์ด์ ์ด ์ฒ๋ฆฌํ ์ ์๊ฒ ํด์ค๋๋ค. ECMAScript 2018์ ๋์ ๋ ๋น๋๊ธฐ ์ดํฐ๋ ์ดํฐ๋ ๋ฐ์ดํฐ ์คํธ๋ฆผ์ ๋น๋๊ธฐ์ ์ผ๋ก ์ฒ๋ฆฌํ๊ธฐ ์ํ ๊ฐ๋ ฅํ ๋ฉ์ปค๋์ฆ์ ์ ๊ณตํฉ๋๋ค. ์ด ๋ธ๋ก๊ทธ ํฌ์คํธ์์๋ ๋น๋๊ธฐ ์ดํฐ๋ ์ดํฐ์ ๊ฐ๋ ์ ์์ธํ ์ดํด๋ณด๊ณ , ์คํธ๋ฆผ ์ฒ๋ฆฌ๋ฅผ ๊ฐ์ํํ๊ธฐ ์ํ ๋น๋๊ธฐ 'for each' ํฌํผ ํจ์๋ฅผ ๊ตฌํํ๋ ๋ฐฉ๋ฒ์ ์์ฐํฉ๋๋ค.
๋น๋๊ธฐ ์ดํฐ๋ ์ดํฐ ์ดํดํ๊ธฐ
๋น๋๊ธฐ ์ดํฐ๋ ์ดํฐ๋ AsyncIterator ์ธํฐํ์ด์ค๋ฅผ ๋ฐ๋ฅด๋ ๊ฐ์ฒด์
๋๋ค. ์ด ๊ฐ์ฒด๋ ๋ ๊ฐ์ง ์์ฑ์ ๊ฐ์ง ๊ฐ์ฒด๋ก ํด์๋๋ ํ๋ก๋ฏธ์ค๋ฅผ ๋ฐํํ๋ next() ๋ฉ์๋๋ฅผ ์ ์ํฉ๋๋ค:
value: ์ํ์ค์ ๋ค์ ๊ฐ์ ๋๋ค.done: ์ดํฐ๋ ์ดํฐ๊ฐ ์๋ฃ๋์๋์ง ์ฌ๋ถ๋ฅผ ๋ํ๋ด๋ ๋ถ๋ฆฌ์ธ ๊ฐ์ ๋๋ค.
๋น๋๊ธฐ ์ดํฐ๋ ์ดํฐ๋ ๋คํธ์ํฌ ์คํธ๋ฆผ, ํ์ผ ์์คํ
๋๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๊ฐ์ ๋น๋๊ธฐ ์์ค๋ก๋ถํฐ ๋ฐ์ดํฐ๋ฅผ ์๋นํ๋ ๋ฐ ํํ ์ฌ์ฉ๋ฉ๋๋ค. for await...of ๋ฃจํ๋ ๋น๋๊ธฐ ์ดํฐ๋ฌ๋ธ์ ๋ฐ๋ณตํ๋ ํธ๋ฆฌํ ๊ตฌ๋ฌธ์ ์ ๊ณตํฉ๋๋ค.
์์ : ๋น๋๊ธฐ์ ์ผ๋ก ํ์ผ ์ฝ๊ธฐ
๋ฉ์ธ ์ค๋ ๋๋ฅผ ์ฐจ๋จํ์ง ์๊ณ ๋์ฉ๋ ํ์ผ์ ํ ์ค์ฉ ์ฝ์ด์ผ ํ๋ ์๋๋ฆฌ์ค๋ฅผ ์๊ฐํด ๋ณด์ธ์. ๋น๋๊ธฐ ์ดํฐ๋ ์ดํฐ๋ฅผ ์ฌ์ฉํ์ฌ ์ด๋ฅผ ๋ฌ์ฑํ ์ ์์ต๋๋ค:
const fs = require('fs');
const readline = require('readline');
async function* readFileLines(filePath) {
const fileStream = fs.createReadStream(filePath);
const rl = readline.createInterface({
input: fileStream,
crlfDelay: Infinity
});
for await (const line of rl) {
yield line;
}
}
async function processFile(filePath) {
for await (const line of readFileLines(filePath)) {
console.log(`Line: ${line}`);
}
}
// Example usage
processFile('path/to/your/file.txt');
์ด ์์ ์์ readFileLines๋ ํ์ผ์ ๊ฐ ์ค์ ์ฝ์ ๋๋ง๋ค yieldํ๋ ๋น๋๊ธฐ ์ ๋๋ ์ดํฐ ํจ์์
๋๋ค. ๊ทธ๋ฐ ๋ค์ processFile ํจ์๋ for await...of๋ฅผ ์ฌ์ฉํ์ฌ ์ค์ ๋ฐ๋ณตํ๋ฉฐ ๊ฐ ์ค์ ๋น๋๊ธฐ์ ์ผ๋ก ์ฒ๋ฆฌํฉ๋๋ค.
๋น๋๊ธฐ 'For Each' ํฌํผ ๊ตฌํํ๊ธฐ
for await...of ๋ฃจํ๋ ์ ์ฉํ์ง๋ง ์คํธ๋ฆผ์ ๊ฐ ์์์ ๋ํด ๋ณต์กํ ์์
์ ์ํํด์ผ ํ ๋๋ ์ฅํฉํด์ง ์ ์์ต๋๋ค. ๋น๋๊ธฐ 'for each' ํฌํผ ํจ์๋ ๋ฐ๋ณต ๋ก์ง์ ์บก์ํํ์ฌ ์ด ๊ณผ์ ์ ๋จ์ํํ ์ ์์ต๋๋ค.
๊ธฐ๋ณธ ๊ตฌํ
๋ค์์ ๋น๋๊ธฐ 'for each' ํจ์์ ๊ธฐ๋ณธ ๊ตฌํ์ ๋๋ค:
async function asyncForEach(iterable, callback) {
for await (const item of iterable) {
await callback(item);
}
}
์ด ํจ์๋ ๋น๋๊ธฐ ์ดํฐ๋ฌ๋ธ๊ณผ ์ฝ๋ฐฑ ํจ์๋ฅผ ์ธ์๋ก ๋ฐ์ต๋๋ค. for await...of๋ฅผ ์ฌ์ฉํ์ฌ ์ดํฐ๋ฌ๋ธ์ ๋ฐ๋ณตํ๊ณ ๊ฐ ํญ๋ชฉ์ ๋ํด ์ฝ๋ฐฑ ํจ์๋ฅผ ํธ์ถํฉ๋๋ค. ๋ค์ ํญ๋ชฉ์ผ๋ก ๋์ด๊ฐ๊ธฐ ์ ์ ์ฝ๋ฐฑ ํจ์์ ์๋ฃ๋ฅผ ๊ธฐ๋ค๋ฆฌ๋ ค๋ฉด ์ฝ๋ฐฑ ํจ์๋ ๋น๋๊ธฐ์ฌ์ผ ํฉ๋๋ค.
์์ : API ๋ฐ์ดํฐ ์ฒ๋ฆฌํ๊ธฐ
ํญ๋ชฉ ์คํธ๋ฆผ์ ๋ฐํํ๋ API์์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์จ๋ค๊ณ ๊ฐ์ ํด ๋ด ์๋ค. ๋น๋๊ธฐ 'for each' ํฌํผ๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ ํญ๋ชฉ์ด ๋์ฐฉํ ๋๋ง๋ค ์ฒ๋ฆฌํ ์ ์์ต๋๋ค:
async function* fetchDataStream(url) {
const response = await fetch(url);
const reader = response.body.getReader();
const decoder = new TextDecoder();
try {
while (true) {
const { done, value } = await reader.read();
if (done) {
return;
}
// Assuming the API returns JSON chunks
const chunk = decoder.decode(value);
const items = JSON.parse(`[${chunk.replace(/\}\{/g, '},{')}]`); //Split chunks into valid json array
for(const item of items){
yield item;
}
}
} finally {
reader.releaseLock();
}
}
async function processItem(item) {
// Simulate an asynchronous operation
await new Promise(resolve => setTimeout(resolve, 100));
console.log(`Processing item: ${JSON.stringify(item)}`);
}
async function main() {
const apiUrl = 'https://api.example.com/data'; // Replace with your API endpoint
await asyncForEach(fetchDataStream(apiUrl), processItem);
console.log('Finished processing data.');
}
// Example usage
main();
์ด ์์ ์์ fetchDataStream์ API์์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ ์์ ๋๋ ๊ฐ ํญ๋ชฉ์ yieldํฉ๋๋ค. processItem ํจ์๋ ๊ฐ ํญ๋ชฉ์ ๋ํ ๋น๋๊ธฐ ์์
์ ์๋ฎฌ๋ ์ด์
ํฉ๋๋ค. ๊ทธ๋ฐ ๋ค์ asyncForEach ํฌํผ๋ ๋ฐ๋ณต ๋ฐ ์ฒ๋ฆฌ ๋ก์ง์ ๋จ์ํํฉ๋๋ค.
๊ฐ์ ์ฌํญ ๋ฐ ๊ณ ๋ ค ์ฌํญ
์ค๋ฅ ์ฒ๋ฆฌ
๋น๋๊ธฐ ๋ฐ๋ณต ์ค์ ๋ฐ์ํ ์ ์๋ ์ค๋ฅ๋ฅผ ์ฒ๋ฆฌํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. ์์ธ๋ฅผ ์ก์ ์ฒ๋ฆฌํ๊ธฐ ์ํด ์ฝ๋ฐฑ ํจ์๋ฅผ try...catch ๋ธ๋ก์ผ๋ก ๊ฐ์ ์ ์์ต๋๋ค:
async function asyncForEach(iterable, callback) {
for await (const item of iterable) {
try {
await callback(item);
} catch (error) {
console.error(`Error processing item: ${item}`, error);
// You can choose to re-throw the error or continue processing
}
}
}
๋์์ฑ ์ ์ด
๊ธฐ๋ณธ์ ์ผ๋ก ๋น๋๊ธฐ 'for each' ํฌํผ๋ ํญ๋ชฉ์ ์์ฐจ์ ์ผ๋ก ์ฒ๋ฆฌํฉ๋๋ค. ํญ๋ชฉ์ ๋์์ ์ฒ๋ฆฌํด์ผ ํ๋ ๊ฒฝ์ฐ ํ๋ก๋ฏธ์ค ํ์ ์ฌ์ฉํ์ฌ ๋์ ์์ ์๋ฅผ ์ ํํ ์ ์์ต๋๋ค:
async function asyncForEachConcurrent(iterable, callback, concurrency) {
const executing = [];
for await (const item of iterable) {
const p = callback(item).then(() => executing.splice(executing.indexOf(p), 1));
executing.push(p);
if (executing.length >= concurrency) {
await Promise.race(executing);
}
}
await Promise.all(executing);
}
async function processItem(item) {
// Simulate an asynchronous operation
await new Promise(resolve => setTimeout(resolve, 100));
console.log(`Processing item: ${JSON.stringify(item)}`);
}
async function main() {
const apiUrl = 'https://api.example.com/data'; // Replace with your API endpoint
await asyncForEachConcurrent(fetchDataStream(apiUrl), processItem, 5); // Concurrency of 5
console.log('Finished processing data.');
}
์ด ์์ ์์ asyncForEachConcurrent๋ ๋์ ์ฝ๋ฐฑ ์คํ ์๋ฅผ ์ง์ ๋ ๋์์ฑ ์์ค์ผ๋ก ์ ํํฉ๋๋ค. ์ด๋ ๋๊ท๋ชจ ๋ฐ์ดํฐ ์คํธ๋ฆผ์ ์ฒ๋ฆฌํ ๋ ์ฑ๋ฅ์ ํฅ์์ํฌ ์ ์์ต๋๋ค.
์ทจ์
๊ฒฝ์ฐ์ ๋ฐ๋ผ ๋ฐ๋ณต ํ๋ก์ธ์ค๋ฅผ ์กฐ๊ธฐ์ ์ทจ์ํด์ผ ํ ์๋ ์์ต๋๋ค. AbortController๋ฅผ ์ฌ์ฉํ์ฌ ์ด๋ฅผ ๋ฌ์ฑํ ์ ์์ต๋๋ค:
async function asyncForEach(iterable, callback, signal) {
for await (const item of iterable) {
if (signal && signal.aborted) {
console.log('Iteration aborted.');
return;
}
await callback(item);
}
}
async function main() {
const controller = new AbortController();
const signal = controller.signal;
setTimeout(() => {
controller.abort(); // Abort after 2 seconds
}, 2000);
const apiUrl = 'https://api.example.com/data'; // Replace with your API endpoint
await asyncForEach(fetchDataStream(apiUrl), processItem, signal);
console.log('Finished processing data.');
}
์ด ์์ ์์ asyncForEach ํจ์๋ ๊ฐ ๋ฐ๋ณต ์ ์ signal.aborted ์์ฑ์ ํ์ธํฉ๋๋ค. ์ ํธ๊ฐ ์ค๋จ๋๋ฉด ๋ฐ๋ณต์ด ์ค์ง๋ฉ๋๋ค.
์ค์ ์ ์ฉ ์ฌ๋ก
๋น๋๊ธฐ ์ดํฐ๋ ์ดํฐ์ ๋น๋๊ธฐ 'for each' ํฌํผ๋ ๋ค์ํ ์ค์ ์๋๋ฆฌ์ค์ ์ ์ฉ๋ ์ ์์ต๋๋ค:
- ๋ฐ์ดํฐ ์ฒ๋ฆฌ ํ์ดํ๋ผ์ธ: ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ ํ์ผ ์์คํ ์ ๋์ฉ๋ ๋ฐ์ดํฐ ์ธํธ ์ฒ๋ฆฌ.
- ์ค์๊ฐ ๋ฐ์ดํฐ ์คํธ๋ฆผ: ์น ์์ผ, ๋ฉ์์ง ํ ๋๋ ์ผ์ ๋คํธ์ํฌ์ ๋ฐ์ดํฐ ์ฒ๋ฆฌ.
- API ์๋น: ํญ๋ชฉ ์คํธ๋ฆผ์ ๋ฐํํ๋ API์์ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ ๋ฐ ์ฒ๋ฆฌ.
- ์ด๋ฏธ์ง ๋ฐ ๋น๋์ค ์ฒ๋ฆฌ: ๋์ฉ๋ ๋ฏธ๋์ด ํ์ผ์ ์ฒญํฌ ๋จ์๋ก ์ฒ๋ฆฌ.
- ๋ก๊ทธ ๋ถ์: ๋์ฉ๋ ๋ก๊ทธ ํ์ผ์ ํ ์ค์ฉ ๋ถ์.
์์ - ๊ตญ์ ์ฃผ์ ๋ฐ์ดํฐ: ๋ค์ํ ๊ตญ์ ๊ฑฐ๋์์์ ์ค์๊ฐ ์ฃผ์ ์์ธ๋ฅผ ๊ฐ์ ธ์ค๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ์๊ฐํด ๋ณด์ธ์. ๋น๋๊ธฐ ์ดํฐ๋ ์ดํฐ๋ฅผ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ๋ฅผ ์คํธ๋ฆฌ๋ฐํ๊ณ , ๋น๋๊ธฐ 'for each'๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ ์์ธ๋ฅผ ์ฒ๋ฆฌํ์ฌ ์ฌ์ฉ์ ์ธํฐํ์ด์ค๋ฅผ ์ต์ ๊ฐ๊ฒฉ์ผ๋ก ์ ๋ฐ์ดํธํ ์ ์์ต๋๋ค. ์ด๋ ๋ค์๊ณผ ๊ฐ์ ํ์ฌ์ ํ์ฌ ์ฃผ๊ฐ๋ฅผ ํ์ํ๋ ๋ฐ ์ฌ์ฉ๋ ์ ์์ต๋๋ค:
- ํ ์ผํธ (์ค๊ตญ): ์ฃผ์ ๊ตญ์ ๊ธฐ์ ๊ธฐ์ ์ ์ฃผ์ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ
- ํํ ์ปจ์คํด์ ์๋น์ค (์ธ๋): ์ ๋์ ์ธ IT ์๋น์ค ๊ธฐ์ ์ ์ฃผ๊ฐ ์ ๋ฐ์ดํธ ํ์
- ์ผ์ฑ์ ์ (๋ํ๋ฏผ๊ตญ): ๊ธ๋ก๋ฒ ์ ์ ์ ์กฐ์ ์ฒด์ ์ฃผ๊ฐ ํ์
- ํ ์ํ ์๋์ฐจ (์ผ๋ณธ): ๊ตญ์ ์๋์ฐจ ์ ์กฐ์ ์ฒด์ ์ฃผ๊ฐ ๋ชจ๋ํฐ๋ง
๊ฒฐ๋ก
๋น๋๊ธฐ ์ดํฐ๋ ์ดํฐ์ ๋น๋๊ธฐ 'for each' ํฌํผ๋ ์๋ฐ์คํฌ๋ฆฝํธ์์ ๋ฐ์ดํฐ ์คํธ๋ฆผ์ ๋น๋๊ธฐ์ ์ผ๋ก ์ฒ๋ฆฌํ๋ ๊ฐ๋ ฅํ๊ณ ์ฐ์ํ ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค. ๋ฐ๋ณต ๋ก์ง์ ์บก์ํํจ์ผ๋ก์จ ์ฝ๋๋ฅผ ๋จ์ํํ๊ณ ๊ฐ๋ ์ฑ์ ๋์ด๋ฉฐ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฑ๋ฅ์ ํฅ์์ํฌ ์ ์์ต๋๋ค. ์ค๋ฅ๋ฅผ ์ฒ๋ฆฌํ๊ณ ๋์์ฑ์ ์ ์ดํ๋ฉฐ ์ทจ์๋ฅผ ํ์ฑํํจ์ผ๋ก์จ ๊ฒฌ๊ณ ํ๊ณ ํ์ฅ ๊ฐ๋ฅํ ๋น๋๊ธฐ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ํ์ดํ๋ผ์ธ์ ๋ง๋ค ์ ์์ต๋๋ค.