ํจ์จ์ ์ธ ๋ฆฌ์์ค ๊ด๋ฆฌ ๋ฐ ์คํธ๋ฆผ ์ ๋ฆฌ ์๋ํ๋ฅผ ์ํ JavaScript ๋น๋๊ธฐ ์ดํฐ๋ ์ดํฐ๋ฅผ ๋ง์คํฐํ์ธ์. ๊ฐ๋ ฅํ๊ณ ํ์ฅ ๊ฐ๋ฅํ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ํ ๋ชจ๋ฒ ์ฌ๋ก, ๊ณ ๊ธ ๊ธฐ์ ๋ฐ ์ค์ ์์ ๋ฅผ ๋ฐฐ์๋๋ค.
JavaScript ๋น๋๊ธฐ ์ดํฐ๋ ์ดํฐ ๋ฆฌ์์ค ๊ด๋ฆฌ: ์คํธ๋ฆผ ์ ๋ฆฌ ์๋ํ
๋น๋๊ธฐ ์ดํฐ๋ ์ดํฐ์ ์ ๋๋ ์ดํฐ๋ JavaScript์์ ๋ฐ์ดํฐ ์คํธ๋ฆผ๊ณผ ๋น๋๊ธฐ ์์ ์ ํจ์จ์ ์ผ๋ก ์ฒ๋ฆฌํ ์ ์๊ฒ ํด์ฃผ๋ ๊ฐ๋ ฅํ ๊ธฐ๋ฅ์ ๋๋ค. ํ์ง๋ง ๋น๋๊ธฐ ํ๊ฒฝ์์ ๋ฆฌ์์ค๋ฅผ ๊ด๋ฆฌํ๊ณ ์ ์ ํ ์ ๋ฆฌ๋ฅผ ๋ณด์ฅํ๋ ๊ฒ์ ์ด๋ ค์ธ ์ ์์ต๋๋ค. ์ฃผ์๋ฅผ ๊ธฐ์ธ์ด์ง ์์ผ๋ฉด ๋ฉ๋ชจ๋ฆฌ ๋์, ๋ซํ์ง ์์ ์ฐ๊ฒฐ ๋ฐ ๊ธฐํ ๋ฆฌ์์ค ๊ด๋ จ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค. ์ด ๊ธฐ์ฌ์์๋ JavaScript ๋น๋๊ธฐ ์ดํฐ๋ ์ดํฐ์์ ์คํธ๋ฆผ ์ ๋ฆฌ๋ฅผ ์๋ํํ๋ ๊ธฐ์ ์ ์ดํด๋ณด๊ณ , ๊ฐ๋ ฅํ๊ณ ํ์ฅ ๊ฐ๋ฅํ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ณด์ฅํ๊ธฐ ์ํ ๋ชจ๋ฒ ์ฌ๋ก์ ์ค์ ์์ ๋ฅผ ์ ๊ณตํฉ๋๋ค.
๋น๋๊ธฐ ์ดํฐ๋ ์ดํฐ ๋ฐ ์ ๋๋ ์ดํฐ ์ดํด
๋ฆฌ์์ค ๊ด๋ฆฌ์ ๋ค์ด๊ฐ๊ธฐ ์ ์ ๋น๋๊ธฐ ์ดํฐ๋ ์ดํฐ์ ์ ๋๋ ์ดํฐ์ ๊ธฐ๋ณธ ์ฌํญ์ ๊ฒํ ํด ๋ณด๊ฒ ์ต๋๋ค.
๋น๋๊ธฐ ์ดํฐ๋ ์ดํฐ
๋น๋๊ธฐ ์ดํฐ๋ ์ดํฐ๋ ๋ ๊ฐ์ง ์์ฑ์ ๊ฐ์ง ๊ฐ์ฒด๋ก ํ์ธ๋๋ Promise๋ฅผ ๋ฐํํ๋ next()
๋ฉ์๋๋ฅผ ์ ์ํ๋ ๊ฐ์ฒด์
๋๋ค.
value
: ์ํ์ค์ ๋ค์ ๊ฐ์ ๋๋ค.done
: ์ดํฐ๋ ์ดํฐ๊ฐ ์๋ฃ๋์๋์ง ์ฌ๋ถ๋ฅผ ๋ํ๋ด๋ ๋ถ์ธ์ ๋๋ค.
๋น๋๊ธฐ ์ดํฐ๋ ์ดํฐ๋ ์ผ๋ฐ์ ์ผ๋ก API ์๋ต ๋๋ ํ์ผ ์คํธ๋ฆผ๊ณผ ๊ฐ์ ๋น๋๊ธฐ ๋ฐ์ดํฐ ์์ค๋ฅผ ์ฒ๋ฆฌํ๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค.
์:
async function* asyncIterable() {
yield 1;
yield 2;
yield 3;
}
async function main() {
for await (const value of asyncIterable()) {
console.log(value);
}
}
main(); // Output: 1, 2, 3
๋น๋๊ธฐ ์ ๋๋ ์ดํฐ
๋น๋๊ธฐ ์ ๋๋ ์ดํฐ๋ ๋น๋๊ธฐ ์ดํฐ๋ ์ดํฐ๋ฅผ ๋ฐํํ๋ ํจ์์
๋๋ค. async function*
๊ตฌ๋ฌธ๊ณผ yield
ํค์๋๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ์ ๋น๋๊ธฐ์ ์ผ๋ก ์์ฑํฉ๋๋ค.
์:
async function* generateSequence(start, end) {
for (let i = start; i <= end; i++) {
await new Promise(resolve => setTimeout(resolve, 500)); // ๋น๋๊ธฐ ์์
์๋ฎฌ๋ ์ด์
yield i;
}
}
async function main() {
for await (const value of generateSequence(1, 5)) {
console.log(value);
}
}
main(); // Output: 1, 2, 3, 4, 5 (๊ฐ ๊ฐ ์ฌ์ด์ 500ms ์ง์ฐ)
๊ณผ์ : ๋น๋๊ธฐ ์คํธ๋ฆผ์ ๋ฆฌ์์ค ๊ด๋ฆฌ
๋น๋๊ธฐ ์คํธ๋ฆผ์ผ๋ก ์์ ํ ๋๋ ๋ฆฌ์์ค๋ฅผ ํจ๊ณผ์ ์ผ๋ก ๊ด๋ฆฌํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. ๋ฆฌ์์ค์๋ ํ์ผ ํธ๋ค, ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ, ๋คํธ์ํฌ ์์ผ ๋๋ ์คํธ๋ฆผ์ ์๋ช ์ฃผ๊ธฐ ๋์ ํ๋ํ๊ณ ํด์ ํด์ผ ํ๋ ๊ธฐํ ์ธ๋ถ ๋ฆฌ์์ค๊ฐ ํฌํจ๋ ์ ์์ต๋๋ค. ์ด๋ฌํ ๋ฆฌ์์ค๋ฅผ ์ ๋๋ก ๊ด๋ฆฌํ์ง ๋ชปํ๋ฉด ๋ค์๊ณผ ๊ฐ์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.
- ๋ฉ๋ชจ๋ฆฌ ๋์: ๋ ์ด์ ํ์ํ์ง ์์ ๋ฆฌ์์ค๊ฐ ํด์ ๋์ง ์์ ์๊ฐ์ด ์ง๋จ์ ๋ฐ๋ผ ์ ์ ๋ ๋ง์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์๋นํฉ๋๋ค.
- ๋ซํ์ง ์์ ์ฐ๊ฒฐ: ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋๋ ๋คํธ์ํฌ ์ฐ๊ฒฐ์ด ์ด๋ฆฐ ์ํ๋ก ์ ์ง๋์ด ์ฐ๊ฒฐ ์ ํ์ ์๋ชจํ๊ณ ์ ์ฌ์ ์ผ๋ก ์ฑ๋ฅ ๋ฌธ์ ๋๋ ์ค๋ฅ๋ฅผ ์ผ์ผํฌ ์ ์์ต๋๋ค.
- ํ์ผ ํธ๋ค ๊ณ ๊ฐ: ์ด๋ฆฐ ํ์ผ ํธ๋ค์ด ๋์ ๋์ด ์ ํ๋ฆฌ์ผ์ด์ ์ด ๋ ๋ง์ ํ์ผ์ ์ด๋ ค๊ณ ํ ๋ ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค.
- ์์ธก ๋ถ๊ฐ๋ฅํ ๋์: ์๋ชป๋ ๋ฆฌ์์ค ๊ด๋ฆฌ๋ ์๊ธฐ์น ์์ ์ค๋ฅ ๋ฐ ์ ํ๋ฆฌ์ผ์ด์ ๋ถ์์ ์ผ๋ก ์ด์ด์ง ์ ์์ต๋๋ค.
๋น๋๊ธฐ ์ฝ๋์ ๋ณต์ก์ฑ, ํนํ ์ค๋ฅ ์ฒ๋ฆฌ๋ก ์ธํด ๋ฆฌ์์ค ๊ด๋ฆฌ๊ฐ ์ด๋ ค์์ง ์ ์์ต๋๋ค. ์คํธ๋ฆผ ์ฒ๋ฆฌ ์ค์ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋๋ผ๋ ๋ฆฌ์์ค๊ฐ ํญ์ ํด์ ๋๋๋ก ํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค.
์คํธ๋ฆผ ์ ๋ฆฌ ์๋ํ: ๊ธฐ์ ๋ฐ ๋ชจ๋ฒ ์ฌ๋ก
๋น๋๊ธฐ ์ดํฐ๋ ์ดํฐ์ ๋ฆฌ์์ค ๊ด๋ฆฌ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ์คํธ๋ฆผ ์ ๋ฆฌ๋ฅผ ์๋ํํ๋ ๋ฐ ์ฌ๋ฌ ๊ธฐ์ ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
1. try...finally
๋ธ๋ก
try...finally
๋ธ๋ก์ ๋ฆฌ์์ค ์ ๋ฆฌ๋ฅผ ๋ณด์ฅํ๋ ๊ธฐ๋ณธ์ ์ธ ๋ฉ์ปค๋์ฆ์
๋๋ค. finally
๋ธ๋ก์ try
๋ธ๋ก์์ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋์ง ์ฌ๋ถ์ ๊ด๊ณ์์ด ํญ์ ์คํ๋ฉ๋๋ค.
์:
async function* readFileLines(filePath) {
let fileHandle;
try {
fileHandle = await fs.open(filePath, 'r');
const stream = fileHandle.readableWebStream();
const reader = stream.getReader();
let decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) {
break;
}
yield decoder.decode(value);
}
} finally {
if (fileHandle) {
await fileHandle.close();
console.log('ํ์ผ ํธ๋ค์ด ๋ซํ์ต๋๋ค.');
}
}
}
async function main() {
try{
for await (const line of readFileLines('example.txt')) {
console.log(line);
}
} catch (error) {
console.error('ํ์ผ ์ฝ๊ธฐ ์ค๋ฅ:', error);
}
}
main();
์ด ์์์ finally
๋ธ๋ก์ ํ์ผ์ ์ฝ๋ ๋์ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋๋ผ๋ ํ์ผ ํธ๋ค์ด ํญ์ ๋ซํ๋๋ก ๋ณด์ฅํฉ๋๋ค.
2. Symbol.asyncDispose
์ฌ์ฉ(๋ช
์์ ๋ฆฌ์์ค ๊ด๋ฆฌ ์ ์)
๋ช
์์ ๋ฆฌ์์ค ๊ด๋ฆฌ ์ ์์ Symbol.asyncDispose
๊ธฐํธ๋ฅผ ๋์
ํ์ฌ ๊ฐ์ฒด๊ฐ ๋ ์ด์ ํ์ํ์ง ์์ ๋ ์๋์ผ๋ก ํธ์ถ๋๋ ๋ฉ์๋๋ฅผ ์ ์ํ ์ ์๋๋ก ํฉ๋๋ค. ์ด๋ C#์ using
๋ฌธ ๋๋ Java์ try-with-resources
๋ฌธ๊ณผ ์ ์ฌํฉ๋๋ค.
์ด ๊ธฐ๋ฅ์ ์์ง ์ ์ ๋จ๊ณ์ ์์ง๋ง ๋ฆฌ์์ค ๊ด๋ฆฌ์ ๋ํ ๋ ๊น๋ํ๊ณ ๊ตฌ์กฐํ๋ ์ ๊ทผ ๋ฐฉ์์ ์ ๊ณตํฉ๋๋ค.
ํ์ฌ ํ๊ฒฝ์์ ์ด๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํ ํด๋ฆฌํ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
์(๊ฐ์ ํด๋ฆฌํ ์ฌ์ฉ):
import { using } from 'resource-management-polyfill';
class MyResource {
constructor() {
console.log('๋ฆฌ์์ค ํ๋.');
}
async [Symbol.asyncDispose]() {
await new Promise(resolve => setTimeout(resolve, 100)); // ๋น๋๊ธฐ ์ ๋ฆฌ ์๋ฎฌ๋ ์ด์
console.log('๋ฆฌ์์ค ํด์ .');
}
}
async function main() {
await using(new MyResource(), async (resource) => {
console.log('๋ฆฌ์์ค ์ฌ์ฉ ์ค...');
// ... ๋ฆฌ์์ค ์ฌ์ฉ
}); // ๋ฆฌ์์ค๋ ์ฌ๊ธฐ์ ์๋์ผ๋ก ์ญ์ ๋ฉ๋๋ค.
console.log('using ๋ธ๋ก ํ.');
}
main();
์ด ์์์ using
๋ฌธ์ ์ค๋ฅ ๋ฐ์ ์ฌ๋ถ์ ๊ด๊ณ์์ด ๋ธ๋ก์ด ์ข
๋ฃ๋ ๋ MyResource
๊ฐ์ฒด์ [Symbol.asyncDispose]
๋ฉ์๋๊ฐ ํธ์ถ๋๋๋ก ๋ณด์ฅํฉ๋๋ค. ์ด๋ ๋ฆฌ์์ค๋ฅผ ํด์ ํ๋ ๊ฒฐ์ ์ ์ด๊ณ ์์ ์ ์ธ ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค.
3. ๋ฆฌ์์ค ๋ํผ ๊ตฌํ
๋ ๋ค๋ฅธ ์ ๊ทผ ๋ฐฉ์์ ๋ฆฌ์์ค ๋ฐ ํด๋น ์ ๋ฆฌ ๋ก์ง์ ์บก์ํํ๋ ๋ฆฌ์์ค ๋ํผ ํด๋์ค๋ฅผ ๋ง๋๋ ๊ฒ์ ๋๋ค. ์ด ํด๋์ค๋ ๋ฆฌ์์ค๋ฅผ ํ๋ํ๊ณ ํด์ ํ๋ ๋ฉ์๋๋ฅผ ๊ตฌํํ์ฌ ์ ๋ฆฌ๊ฐ ํญ์ ์ฌ๋ฐ๋ฅด๊ฒ ์ํ๋๋๋ก ํ ์ ์์ต๋๋ค.
์:
class FileStreamResource {
constructor(filePath) {
this.filePath = filePath;
this.fileHandle = null;
}
async acquire() {
this.fileHandle = await fs.open(this.filePath, 'r');
console.log('ํ์ผ ํธ๋ค ํ๋.');
return this.fileHandle.readableWebStream();
}
async release() {
if (this.fileHandle) {
await this.fileHandle.close();
console.log('ํ์ผ ํธ๋ค ํด์ .');
this.fileHandle = null;
}
}
}
async function* readFileLines(resource) {
try {
const stream = await resource.acquire();
const reader = stream.getReader();
let decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) {
break;
}
yield decoder.decode(value);
}
} finally {
await resource.release();
}
}
async function main() {
const fileResource = new FileStreamResource('example.txt');
try {
for await (const line of readFileLines(fileResource)) {
console.log(line);
}
} catch (error) {
console.error('ํ์ผ ์ฝ๊ธฐ ์ค๋ฅ:', error);
}
}
main();
์ด ์์์ FileStreamResource
ํด๋์ค๋ ํ์ผ ํธ๋ค๊ณผ ํด๋น ์ ๋ฆฌ ๋ก์ง์ ์บก์ํํฉ๋๋ค. readFileLines
์ ๋๋ ์ดํฐ๋ ์ด ํด๋์ค๋ฅผ ์ฌ์ฉํ์ฌ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋๋ผ๋ ํ์ผ ํธ๋ค์ด ํญ์ ํด์ ๋๋๋ก ๋ณด์ฅํฉ๋๋ค.
4. ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ฐ ํ๋ ์์ํฌ ํ์ฉ
๋ง์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ํ๋ ์์ํฌ๋ ๋ฆฌ์์ค ๊ด๋ฆฌ ๋ฐ ์คํธ๋ฆผ ์ ๋ฆฌ๋ฅผ ์ํ ๊ธฐ๋ณธ ์ ๊ณต ๋ฉ์ปค๋์ฆ์ ์ ๊ณตํฉ๋๋ค. ์ด๋ฅผ ํตํด ํ๋ก์ธ์ค๋ฅผ ๋จ์ํํ๊ณ ์ค๋ฅ ์ํ์ ์ค์ผ ์ ์์ต๋๋ค.
- Node.js Streams API: Node.js Streams API๋ ์คํธ๋ฆฌ๋ฐ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ๋ ๊ฐ๋ ฅํ๊ณ ํจ์จ์ ์ธ ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค. ์ฌ๊ธฐ์๋ ๋ฐฑํ๋ ์ ๋ฅผ ๊ด๋ฆฌํ๊ณ ์ ์ ํ ์ ๋ฆฌ๋ฅผ ๋ณด์ฅํ๊ธฐ ์ํ ๋ฉ์ปค๋์ฆ์ด ํฌํจ๋์ด ์์ต๋๋ค.
- RxJS(JavaScript์ฉ Reactive Extensions): RxJS๋ ๋น๋๊ธฐ ๋ฐ์ดํฐ ์คํธ๋ฆผ์ ๊ด๋ฆฌํ๊ธฐ ์ํ ๊ฐ๋ ฅํ ๋๊ตฌ๋ฅผ ์ ๊ณตํ๋ ๋ฐ์ํ ํ๋ก๊ทธ๋๋ฐ์ฉ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๋ค. ์ฌ๊ธฐ์๋ ์ค๋ฅ ์ฒ๋ฆฌ, ์์ ์ฌ์๋ ๋ฐ ๋ฆฌ์์ค ์ ๋ฆฌ๋ฅผ ๋ณด์ฅํ๊ธฐ ์ํ ์ฐ์ฐ์๊ฐ ํฌํจ๋์ด ์์ต๋๋ค.
- ์๋ ์ ๋ฆฌ ๊ธฐ๋ฅ์ด ์๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ: ์ผ๋ถ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ฐ ๋คํธ์ํน ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ์๋ ์ฐ๊ฒฐ ํ๋ง ๋ฐ ๋ฆฌ์์ค ํด์ ๋ฅผ ํตํด ์ค๊ณ๋์์ต๋๋ค.
์(Node.js Streams API ์ฌ์ฉ):
const fs = require('node:fs');
const { pipeline } = require('node:stream/promises');
const { Transform } = require('node:stream');
async function main() {
try {
await pipeline(
fs.createReadStream('example.txt'),
new Transform({
transform(chunk, encoding, callback) {
this.push(chunk.toString().toUpperCase());
callback();
}
}),
fs.createWriteStream('output.txt')
);
console.log('ํ์ดํ๋ผ์ธ ์ฑ๊ณต.');
} catch (err) {
console.error('ํ์ดํ๋ผ์ธ ์คํจ.', err);
}
}
main();
์ด ์์์ pipeline
ํจ์๋ ์คํธ๋ฆผ์ ์๋์ผ๋ก ๊ด๋ฆฌํ์ฌ ์คํธ๋ฆผ์ด ์ ๋๋ก ๋ซํ๊ณ ์ค๋ฅ๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ์ฒ๋ฆฌ๋๋๋ก ๋ณด์ฅํฉ๋๋ค.
๋ฆฌ์์ค ๊ด๋ฆฌ๋ฅผ ์ํ ๊ณ ๊ธ ๊ธฐ์
๊ธฐ๋ณธ ๊ธฐ์ ์ธ์๋ ์ฌ๋ฌ ๊ณ ๊ธ ์ ๋ต์ ํตํด ๋น๋๊ธฐ ์ดํฐ๋ ์ดํฐ์ ๋ฆฌ์์ค ๊ด๋ฆฌ๋ฅผ ๋์ฑ ํฅ์์ํฌ ์ ์์ต๋๋ค.
1. ์ทจ์ ํ ํฐ
์ทจ์ ํ ํฐ์ ๋น๋๊ธฐ ์์ ์ ์ทจ์ํ๊ธฐ ์ํ ๋ฉ์ปค๋์ฆ์ ์ ๊ณตํฉ๋๋ค. ์ด๋ ์ฌ์ฉ์๊ฐ ์์ฒญ์ ์ทจ์ํ๊ฑฐ๋ ์๊ฐ ์ด๊ณผ๊ฐ ๋ฐ์ํ๋ ๊ฒฝ์ฐ์ ๊ฐ์ด ๋ ์ด์ ํ์ํ์ง ์์ ์์ ์์ ๋ฆฌ์์ค๋ฅผ ํด์ ํ๋ ๋ฐ ์ ์ฉํ ์ ์์ต๋๋ค.
์:
class CancellationToken {
constructor() {
this.isCancelled = false;
this.listeners = [];
}
cancel() {
this.isCancelled = true;
for (const listener of this.listeners) {
listener();
}
}
register(listener) {
this.listeners.push(listener);
return () => {
this.listeners = this.listeners.filter(l => l !== listener);
};
}
}
async function* fetchData(url, cancellationToken) {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP ์ค๋ฅ! ์ํ: ${response.status}`);
}
const reader = response.body.getReader();
const decoder = new TextDecoder();
while (true) {
if (cancellationToken.isCancelled) {
console.log('Fetch ์ทจ์๋จ.');
reader.cancel(); // ์คํธ๋ฆผ ์ทจ์
return;
}
const { done, value } = await reader.read();
if (done) {
break;
}
yield decoder.decode(value);
}
} catch (error) {
console.error('๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ ์ค๋ฅ:', error);
}
}
async function main() {
const cancellationToken = new CancellationToken();
const url = 'https://example.com/data'; // ์ ํจํ URL๋ก ๋ฐ๊พธ์ญ์์ค.
setTimeout(() => {
cancellationToken.cancel(); // 3์ด ํ ์ทจ์
}, 3000);
try {
for await (const chunk of fetchData(url, cancellationToken)) {
console.log(chunk);
}
} catch (error) {
console.error('๋ฐ์ดํฐ ์ฒ๋ฆฌ ์ค๋ฅ:', error);
}
}
main();
์ด ์์์ fetchData
์ ๋๋ ์ดํฐ๋ ์ทจ์ ํ ํฐ์ ํ์ฉํฉ๋๋ค. ํ ํฐ์ด ์ทจ์๋๋ฉด ์ ๋๋ ์ดํฐ๋ ๊ฐ์ ธ์ค๊ธฐ ์์ฒญ์ ์ทจ์ํ๊ณ ์ฐ๊ฒฐ๋ ๋ฆฌ์์ค๋ฅผ ํด์ ํฉ๋๋ค.
2. WeakRefs ๋ฐ FinalizationRegistry
WeakRef
๋ฐ FinalizationRegistry
๋ ๊ฐ์ฒด ์๋ช
์ฃผ๊ธฐ๋ฅผ ์ถ์ ํ๊ณ ๊ฐ์ฒด๊ฐ ๊ฐ๋น์ง ์์ง๋ ๋ ์ ๋ฆฌ๋ฅผ ์ํํ ์ ์๋ ๊ณ ๊ธ ๊ธฐ๋ฅ์
๋๋ค. ์ด๋ ๋ค๋ฅธ ๊ฐ์ฒด์ ์๋ช
์ฃผ๊ธฐ์ ์ฐ๊ฒฐ๋ ๋ฆฌ์์ค๋ฅผ ๊ด๋ฆฌํ๋ ๋ฐ ์ ์ฉํ ์ ์์ต๋๋ค.
์ฐธ๊ณ : ์ด๋ฌํ ๊ธฐ์ ์ ๊ฐ๋น์ง ์์ง ๋์์ ์์กดํ๋ฏ๋ก ์์ธกํ ์ ์๋ ๊ฒฝ์ฐ๊ฐ ์์ผ๋ฏ๋ก ์ ์คํ๊ฒ ์ฌ์ฉํ์ญ์์ค.
์:
const registry = new FinalizationRegistry(heldValue => {
console.log(`์ ๋ฆฌ: ${heldValue}`);
// ์ฌ๊ธฐ์ ์ ๋ฆฌ ์ํ(์: ์ฐ๊ฒฐ ๋ซ๊ธฐ)
});
class MyObject {
constructor(id) {
this.id = id;
registry.register(this, `Object ${id}`, this);
}
}
let obj1 = new MyObject(1);
let obj2 = new MyObject(2);
// ... ๋์ค์ obj1๊ณผ obj2๊ฐ ๋ ์ด์ ์ฐธ์กฐ๋์ง ์๋ ๊ฒฝ์ฐ:
// obj1 = null;
// obj2 = null;
// ๊ฐ๋น์ง ์์ง์ ๊ฒฐ๊ตญ FinalizationRegistry๋ฅผ ํธ๋ฆฌ๊ฑฐํฉ๋๋ค.
// ์ ๋ฆฌ ๋ฉ์์ง๊ฐ ๊ธฐ๋ก๋ฉ๋๋ค.
3. ์ค๋ฅ ๊ฒฝ๊ณ ๋ฐ ๋ณต๊ตฌ
์ค๋ฅ ๊ฒฝ๊ณ๋ฅผ ๊ตฌํํ๋ฉด ์ค๋ฅ๊ฐ ์ ํ๋์ด ์ ์ฒด ์คํธ๋ฆผ์ ์ค๋จ์ํค๋ ๊ฒ์ ๋ฐฉ์งํ๋ ๋ฐ ๋์์ด ๋ ์ ์์ต๋๋ค. ์ค๋ฅ ๊ฒฝ๊ณ๋ ์ค๋ฅ๋ฅผ ํฌ์ฐฉํ๊ณ ์คํธ๋ฆผ์ ๋ณต๊ตฌํ๊ฑฐ๋ ์ ์์ ์ผ๋ก ์ข ๋ฃํ๊ธฐ ์ํ ๋ฉ์ปค๋์ฆ์ ์ ๊ณตํ ์ ์์ต๋๋ค.
์:
async function* processData(dataStream) {
try {
for await (const data of dataStream) {
try {
// ์ฒ๋ฆฌ ์ค ์ ์ฌ์ ์ธ ์ค๋ฅ ์๋ฎฌ๋ ์ด์
if (Math.random() < 0.1) {
throw new Error('์ฒ๋ฆฌ ์ค๋ฅ!');
}
yield `์ฒ๋ฆฌ๋จ: ${data}`;
} catch (error) {
console.error('๋ฐ์ดํฐ ์ฒ๋ฆฌ ์ค๋ฅ:', error);
// ๋ฌธ์ ์๋ ๋ฐ์ดํฐ ๋ณต๊ตฌ ๋๋ ๊ฑด๋๋ฐ๊ธฐ
yield `์ค๋ฅ: ${error.message}`;
}
}
} catch (error) {
console.error('์คํธ๋ฆผ ์ค๋ฅ:', error);
// ์คํธ๋ฆผ ์ค๋ฅ ์ฒ๋ฆฌ(์: ๋ก๊น
, ์ข
๋ฃ)
}
}
async function* generateData() {
for (let i = 0; i < 10; i++) {
await new Promise(resolve => setTimeout(resolve, 100));
yield `Data ${i}`;
}
}
async function main() {
for await (const result of processData(generateData())) {
console.log(result);
}
}
main();
์ค์ ์์ ๋ฐ ์ฌ์ฉ ์ฌ๋ก
์๋ํ๋ ์คํธ๋ฆผ ์ ๋ฆฌ๊ฐ ์ค์ํ ๋ช ๊ฐ์ง ์ค์ ์์ ๋ฐ ์ฌ์ฉ ์ฌ๋ก๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
1. ๋์ฉ๋ ํ์ผ ์คํธ๋ฆฌ๋ฐ
๋์ฉ๋ ํ์ผ์ ์คํธ๋ฆฌ๋ฐํ ๋๋ ์ฒ๋ฆฌ ํ ํ์ผ ํธ๋ค์ด ์ ๋๋ก ๋ซํ๋๋ก ํ๋ ๊ฒ์ด ํ์์ ์ ๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ํ์ผ ํธ๋ค ๊ณ ๊ฐ์ ๋ฐฉ์งํ๊ณ ํ์ผ์ด ๋ฌด๊ธฐํ์ผ๋ก ์ด๋ฆฐ ์ํ๋ก ์ ์ง๋์ง ์๋๋ก ํ ์ ์์ต๋๋ค.
์(๋์ฉ๋ CSV ํ์ผ ์ฝ๊ธฐ ๋ฐ ์ฒ๋ฆฌ):
const fs = require('node:fs');
const readline = require('node:readline');
async function processLargeCSV(filePath) {
const fileStream = fs.createReadStream(filePath);
const rl = readline.createInterface({
input: fileStream,
crlfDelay: Infinity
});
try {
for await (const line of rl) {
// CSV ํ์ผ์ ๊ฐ ์ค ์ฒ๋ฆฌ
console.log(`์ฒ๋ฆฌ ์ค: ${line}`);
}
} finally {
fileStream.close(); // ํ์ผ ์คํธ๋ฆผ์ด ๋ซํ๋๋ก ํฉ๋๋ค.
console.log('ํ์ผ ์คํธ๋ฆผ์ด ๋ซํ์ต๋๋ค.');
}
}
async function main() {
try{
await processLargeCSV('large_data.csv');
} catch (error) {
console.error('CSV ์ฒ๋ฆฌ ์ค๋ฅ:', error);
}
}
main();
2. ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ ์ฒ๋ฆฌ
๋ฐ์ดํฐ๋ฒ ์ด์ค๋ก ์์ ํ ๋๋ ๋ ์ด์ ํ์ํ์ง ์์ ์ฐ๊ฒฐ์ ํด์ ํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ์ฐ๊ฒฐ ๊ณ ๊ฐ์ ๋ฐฉ์งํ๊ณ ๋ฐ์ดํฐ๋ฒ ์ด์ค๊ฐ ๋ค๋ฅธ ์์ฒญ์ ์ฒ๋ฆฌํ ์ ์๋๋ก ํ ์ ์์ต๋๋ค.
์(๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๊ณ ์ฐ๊ฒฐ ๋ซ๊ธฐ):
const { Pool } = require('pg');
async function fetchDataFromDatabase(query) {
const pool = new Pool({
user: 'dbuser',
host: 'localhost',
database: 'mydb',
password: 'dbpassword',
port: 5432
});
let client;
try {
client = await pool.connect();
const result = await client.query(query);
return result.rows;
} finally {
if (client) {
client.release(); // ์ฐ๊ฒฐ์ ํ๋ก ๋ค์ ํด์
console.log('๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ์ด ํด์ ๋์์ต๋๋ค.');
}
}
}
async function main() {
try{
const data = await fetchDataFromDatabase('SELECT * FROM mytable');
console.log('๋ฐ์ดํฐ:', data);
} catch (error) {
console.error('๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ ์ค๋ฅ:', error);
}
}
main();
3. ๋คํธ์ํฌ ์คํธ๋ฆผ ์ฒ๋ฆฌ
๋คํธ์ํฌ ์คํธ๋ฆผ์ ์ฒ๋ฆฌํ ๋๋ ๋ฐ์ดํฐ๊ฐ ์์ ๋ ํ ์์ผ ๋๋ ์ฐ๊ฒฐ์ ๋ซ๋ ๊ฒ์ด ํ์์ ์ ๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ๋ฆฌ์์ค ๋์๋ฅผ ๋ฐฉ์งํ๊ณ ์๋ฒ๊ฐ ๋ค๋ฅธ ์ฐ๊ฒฐ์ ์ฒ๋ฆฌํ ์ ์๋๋ก ํ ์ ์์ต๋๋ค.
์(์๊ฒฉ API์์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๊ณ ์ฐ๊ฒฐ ๋ซ๊ธฐ):
const https = require('node:https');
async function fetchDataFromAPI(url) {
return new Promise((resolve, reject) => {
const req = https.get(url, (res) => {
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
resolve(JSON.parse(data));
});
});
req.on('error', (error) => {
reject(error);
});
req.on('close', () => {
console.log('์ฐ๊ฒฐ์ด ๋ซํ์ต๋๋ค.');
});
});
}
async function main() {
try {
const data = await fetchDataFromAPI('https://jsonplaceholder.typicode.com/todos/1');
console.log('๋ฐ์ดํฐ:', data);
} catch (error) {
console.error('๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ ์ค๋ฅ:', error);
}
}
main();
๊ฒฐ๋ก
ํจ์จ์ ์ธ ๋ฆฌ์์ค ๊ด๋ฆฌ์ ์๋ํ๋ ์คํธ๋ฆผ ์ ๋ฆฌ๋ ๊ฐ๋ ฅํ๊ณ ํ์ฅ ๊ฐ๋ฅํ JavaScript ์ ํ๋ฆฌ์ผ์ด์
์ ๊ตฌ์ถํ๋ ๋ฐ ์ค์ํฉ๋๋ค. ๋น๋๊ธฐ ์ดํฐ๋ ์ดํฐ์ ์ ๋๋ ์ดํฐ๋ฅผ ์ดํดํ๊ณ try...finally
๋ธ๋ก, Symbol.asyncDispose
(์ฌ์ฉ ๊ฐ๋ฅํ ๊ฒฝ์ฐ), ๋ฆฌ์์ค ๋ํผ, ์ทจ์ ํ ํฐ ๋ฐ ์ค๋ฅ ๊ฒฝ๊ณ์ ๊ฐ์ ๊ธฐ์ ์ ์ฌ์ฉํ์ฌ ๊ฐ๋ฐ์๋ ์ค๋ฅ ๋๋ ์ทจ์์ ์ง๋ฉดํ๋๋ผ๋ ๋ฆฌ์์ค๊ฐ ํญ์ ํด์ ๋๋๋ก ํ ์ ์์ต๋๋ค.
๊ธฐ๋ณธ ์ ๊ณต ๋ฆฌ์์ค ๊ด๋ฆฌ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ฐ ํ๋ ์์ํฌ๋ฅผ ํ์ฉํ๋ฉด ํ๋ก์ธ์ค๋ฅผ ๋์ฑ ๋จ์ํํ๊ณ ์ค๋ฅ ์ํ์ ์ค์ผ ์ ์์ต๋๋ค. ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ๋ฐ๋ฅด๊ณ ๋ฆฌ์์ค ๊ด๋ฆฌ์ ์ฃผ์๋ฅผ ๊ธฐ์ธ์์ผ๋ก์จ ๊ฐ๋ฐ์๋ ์์ ์ ์ด๊ณ ํจ์จ์ ์ด๋ฉฐ ์ ์ง ๊ด๋ฆฌ ๊ฐ๋ฅํ ๋น๋๊ธฐ ์ฝ๋๋ฅผ ๋ง๋ค์ด ๋ค์ํ ๊ธ๋ก๋ฒ ํ๊ฒฝ์์ ์ ํ๋ฆฌ์ผ์ด์ ์ฑ๋ฅ๊ณผ ์์ ์ฑ์ ํฅ์์ํฌ ์ ์์ต๋๋ค.
์ถ๊ฐ ํ์ต
- MDN Web Docs์ ๋น๋๊ธฐ ์ดํฐ๋ ์ดํฐ ๋ฐ ์ ๋๋ ์ดํฐ: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for-await...of
- Node.js Streams API ์ค๋ช ์: https://nodejs.org/api/stream.html
- RxJS ์ค๋ช ์: https://rxjs.dev/
- ๋ช ์์ ๋ฆฌ์์ค ๊ด๋ฆฌ ์ ์: https://github.com/tc39/proposal-explicit-resource-management
์ฌ๊ธฐ์ ์ ์๋ ์์ ์ ๊ธฐ์ ์ ํน์ ์ฌ์ฉ ์ฌ๋ก์ ํ๊ฒฝ์ ๋ง๊ฒ ์กฐ์ ํ๊ณ ํญ์ ๋ฆฌ์์ค ๊ด๋ฆฌ๋ฅผ ์ฐ์ ์ํ์ฌ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฅ๊ธฐ์ ์ธ ๊ฑด์ ์ฑ๊ณผ ์์ ์ฑ์ ๋ณด์ฅํ์ญ์์ค.