ìë°ì€í¬ëŠœíž ëì í ìì ì ë³µì¡ì±ì í구íê³ , ê²¬ê³ íê³ íì¥ ê°ë¥í ì í늬ìŒìŽì ì ìí ì€ë ë ìì í êŽëЬ êž°ì ì ìŽì ì ë§ì¶¥ëë€.
ìë°ì€í¬ëŠœíž ëì í ìì : ì€ë ë ìì í êŽëЬ
íë ì¹ ê°ë°ì ìžê³ìì ìë°ì€í¬ëŠœížì ë¹ëêž°ì í¹ì±ì ì¶ë³µìž ëìì ì ì¬ì ìž ë³µì¡ì±ì ììžìŽêž°ë í©ëë€. ì í늬ìŒìŽì ì ì구ì¬íìŽ ì ì ë ëìì§ì ë°ëŒ, ëì ìì ì íšìšì ìŒë¡ ì²ëЬíë ê²ìŽ ì€ìíŽì¡ìµëë€. ìŽë¬í ìì ì êŽëЬíêž° ìí Ʞ볞ì ìž ìë£ êµ¬ì¡° ì€ íëê° íì ëë€. ìŽ êžììë ìë°ì€í¬ëŠœížìì ëì í ìì ì 구ííë ë³µì¡í 묞ì ë€ì ê¹ìŽ íê³ ë€ë©°, ë°ìŽí° 묎결ì±ê³Œ ì í늬ìŒìŽì ìì ì±ì 볎ì¥íêž° ìí ì€ë ë ìì í êŽëЬ êž°ì ì ìŽì ì ë§ì¶¥ëë€.
ëìì±ê³Œ ë¹ëêž° ìë°ì€í¬ëŠœížì ìŽíŽ
ìë°ì€í¬ëŠœížë ëšìŒ ì€ë ë í¹ì±ì ëìì±ì ë¬ì±íêž° ìíŽ ë¹ëêž° íë¡ê·žëë°ì í¬ê² ì졎í©ëë€. ë©ìž ì€ë ëìì ì§ì í ì믞ì ë³ë ¬ ì²ëЬë ì§ì ì ìŒë¡ ë¶ê°ë¥íì§ë§, ë¹ëêž° ìì ì íµíŽ ìì ì ëìì ìíí ì ììŽ UI ëžë¡í¹ì ë°©ì§íê³ ë°ìì±ì í¥ììí¬ ì ììµëë€. ê·žë¬ë ì¬ë¬ ë¹ëêž° ìì ìŽ íì ê°ì ê³µì ìì곌 ìíž ìì©íŽìŒ í ë ì ì í ëêž°íê° ììŒë©Ž 겜ì ìí(race condition) ë° ë°ìŽí° ìììŽ ë°ìí ì ììµëë€. ë°ë¡ ìŽ ì§ì ìì ì€ë ë ìì í êŽëŠ¬ê° íìì ìŽ ë©ëë€.
ì€ë ë ìì íì íìì±
ì€ë ë ìì íë ë°ìŽí° 묎결ì±ì ìììí€ì§ ììŒë©Žì ì¬ë¬ 'ì€ë ë' ëë ë¹ëêž° ìì ì ëì ì ê·Œì ì²ëЬíëë¡ ì€ê³ëììµëë€. ìŽë í ìì (enqueue, dequeue, peek ë±)ìŽ ììì (atomic)ìì 볎ì¥íë©°, ìŽë ëšìŒíê³ ë¶í í ì ìë ëšìë¡ ì€íëšì ì믞í©ëë€. ìŽë¥Œ íµíŽ ì¬ë¬ ìì ìŽ ìë¡ ê°ìíì¬ ììž¡í ì ìë 결곌륌 ìŽëíë 겜ì ìí륌 ë°©ì§í©ëë€. ì¬ë¬ ì¬ì©ìê° ëìì ì²ëЬí ìì ì íì ì¶ê°íë ìë늬ì€ë¥Œ ìê°íŽë³Žììì€. ì€ë ë ìì ì±ìŽ ìë€ë©Ž ìì ìŽ ìì€ëê±°ë, ì€ë³µëê±°ë, ì못ë ììë¡ ì²ëЬë ì ììµëë€.
ìë°ì€í¬ëŠœížì Ʞ볞 í 구í
ì€ë ë ìì 구íì ëíŽ ìì볎Ʞ ì ì, ìë°ì€í¬ëŠœížì Ʞ볞 í 구íì ìŽíŽë³Žê² ìµëë€:
class Queue {
constructor() {
this.items = [];
}
enqueue(element) {
this.items.push(element);
}
dequeue() {
if (this.isEmpty()) {
return "Underflow";
}
return this.items.shift();
}
peek() {
if (this.isEmpty()) {
return "No elements in Queue";
}
return this.items[0];
}
isEmpty() {
return this.items.length == 0;
}
printQueue() {
let str = "";
for (let i = 0; i < this.items.length; i++) {
str += this.items[i] + " ";
}
return str;
}
}
// Example Usage
let queue = new Queue();
queue.enqueue(10);
queue.enqueue(20);
queue.enqueue(30);
console.log(queue.printQueue()); // Output: 10 20 30
console.log(queue.dequeue()); // Output: 10
console.log(queue.peek()); // Output: 20
ìŽ êž°ë³ž 구íì ì€ë ë ìì íì§ ììµëë€. ì¬ë¬ ë¹ëêž° ìì ìŽ ìŽ íì ëìì ì ê·Œí멎, í¹í ìží(enqueue) ë° ëí(dequeue) ìì 겜ì ìíê° ë°ìí ì ììµëë€.
ìë°ì€í¬ëŠœížì ì€ë ë ìì í êŽëЬ ì ê·Œë²
ìë°ì€í¬ëŠœíž íìì ì€ë ë ìì ì±ì ë¬ì±íë €ë©Ž íì Ʞ볞 ë°ìŽí° 구조ì ëí ì ê·Œì ëêž°ííêž° ìí ë€ìí êž°ì ì ì¬ì©íŽìŒ í©ëë€. ë€ìì ëª ê°ì§ ìŒë°ì ìž ì ê·Œë²ì ëë€:
1. Async/Awaitì íšê» 뮀í ì€(Mutex, ìíž ë°°ì ) ì¬ì©íêž°
뮀í ì€ë í ë²ì íëì 'ì€ë ë' ëë ë¹ëêž° ìì ë§ ê³µì ììì ì ê·Œí ì ìëë¡ íì©íë ì êž ë©ì»€ëìŠì ëë€. `async/await`ì ê°ì ë¹ëêž° Ʞ볞 ììì ê°ëší íë귞륌 ì¬ì©íì¬ ë®€í ì€ë¥Œ 구íí ì ììµëë€.
class Mutex {
constructor() {
this.locked = false;
this.queue = [];
}
async lock() {
return new Promise((resolve) => {
if (!this.locked) {
this.locked = true;
resolve();
} else {
this.queue.push(resolve);
}
});
}
unlock() {
if (this.queue.length > 0) {
const resolve = this.queue.shift();
resolve();
} else {
this.locked = false;
}
}
}
class ThreadSafeQueue {
constructor() {
this.items = [];
this.mutex = new Mutex();
}
async enqueue(element) {
await this.mutex.lock();
try {
this.items.push(element);
} finally {
this.mutex.unlock();
}
}
async dequeue() {
await this.mutex.lock();
try {
if (this.isEmpty()) {
return "Underflow";
}
return this.items.shift();
} finally {
this.mutex.unlock();
}
}
async peek() {
await this.mutex.lock();
try {
if (this.isEmpty()) {
return "No elements in Queue";
}
return this.items[0];
} finally {
this.mutex.unlock();
}
}
async isEmpty() {
await this.mutex.lock();
try {
return this.items.length === 0;
} finally {
this.mutex.unlock();
}
}
async printQueue() {
await this.mutex.lock();
try {
let str = "";
for (let i = 0; i < this.items.length; i++) {
str += this.items[i] + " ";
}
return str;
} finally {
this.mutex.unlock();
}
}
}
// Example Usage
async function example() {
let queue = new ThreadSafeQueue();
await queue.enqueue(10);
await queue.enqueue(20);
await queue.enqueue(30);
console.log(await queue.printQueue());
console.log(await queue.dequeue());
console.log(await queue.peek());
}
example();
ìŽ êµ¬íìì `Mutex` íŽëì€ë í ë²ì íëì ìì ë§ìŽ `items` ë°°ìŽì ì ê·Œí ì ìëë¡ ë³Žì¥í©ëë€. `lock()` ë©ìëë 뮀í ì€ë¥Œ íëíê³ , `unlock()` ë©ìëë ìŽë¥Œ íŽì í©ëë€. `try...finally` ëžë¡ì ìê³ êµ¬ì(critical section) ëŽìì ì€ë¥ê° ë°ìíëëŒë 뮀í ì€ê° íì íŽì ëëë¡ ë³Žì¥í©ëë€. ìŽë êµì°© ìí(deadlock)륌 ë°©ì§íë ë° ë§€ì° ì€ìí©ëë€.
2. SharedArrayBuffer ë° ì컀 ì€ë ëì íšê» Atomics ì¬ì©íêž°
ì§ì í ë³ë ¬ ì²ëŠ¬ê° í¬íšë ë ë³µì¡í ìë늬ì€ì 겜ì°, ììì ì°ì°ê³Œ íšê» `SharedArrayBuffer` ë° `Worker` ì€ë ë륌 íì©í ì ììµëë€. ìŽ ì ê·Œë²ì ì¬ë¬ ì€ë ëê° ê³µì ë©ëªšëЬì ì ê·Œíëë¡ íì©íì§ë§, ë°ìŽí° 겜ì(data race)ì ë°©ì§íêž° ìíŽ ììì ì°ì°ì ì¬ì©í ìžì¬í ëêž°íê° íìí©ëë€.
ì°žê³ : `SharedArrayBuffer`륌 ì¬ì©íë €ë©Ž ìë°ì€í¬ëŠœíž ìœë륌 ì ê³µíë ìë²ìì í¹ì HTTP í€ë(`Cross-Origin-Opener-Policy` ë° `Cross-Origin-Embedder-Policy`)륌 ì¬ë°ë¥Žê² ì€ì íŽìŒ í©ëë€. ë¡ì»¬ìì ì€ííë 겜ì°, ëžëŒì°ì ê° ê³µì ë©ëªšëЬ ì ê·Œì ì°šëší ì ììµëë€. ê³µì ë©ëªšëЬ íì±íì ëí ììží ëŽì©ì ëžëŒì°ì ì€ëª ì륌 ì°žì¡°íììì€.
ì€ì: ë€ì ìì ë ê°ë ì ìž ìì°ìŽë©° í¹ì ì¬ì© ì¬ë¡ì ë°ëŒ ìë¹í ìì ìŽ íìí ì ììµëë€. `SharedArrayBuffer`ì `Atomics`륌 ì¬ë°ë¥Žê² ì¬ì©íë ê²ì ë³µì¡íë©° ë°ìŽí° 겜ì ë° êž°í ëìì± ë¬žì 륌 íŒíêž° ìíŽ ìžë¶ ì¬íì ìžì¬í 죌ìê° íìí©ëë€.
ë©ìž ì€ë ë (main.js):
// main.js
const worker = new Worker('worker.js');
const buffer = new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 1024); // Example: 1024 integers
const queue = new Int32Array(buffer);
const headIndex = 0; // First element in the buffer
const tailIndex = 1; // Second element in the buffer
const dataStartIndex = 2; // Third element and onward hold the queue data
Atomics.store(queue, headIndex, 0);
Atomics.store(queue, tailIndex, 0);
worker.postMessage({ buffer });
// Example: Enqueue from the main thread
function enqueue(value) {
let tail = Atomics.load(queue, tailIndex);
const nextTail = (tail + 1) % (queue.length - dataStartIndex + dataStartIndex);
// Check if the queue is full (wrapping around)
let head = Atomics.load(queue, headIndex);
if (nextTail === head) {
console.log("Queue is full.");
return;
}
Atomics.store(queue, dataStartIndex + tail, value); // Store the value
Atomics.store(queue, tailIndex, nextTail); // Increment tail
console.log("Enqueued " + value + " from main thread");
}
// Example: Dequeue from the main thread (similar to enqueue)
function dequeue() {
let head = Atomics.load(queue, headIndex);
if (head === Atomics.load(queue, tailIndex)) {
console.log("Queue is empty.");
return null;
}
const value = Atomics.load(queue, dataStartIndex + head);
const nextHead = (head + 1) % (queue.length - dataStartIndex + dataStartIndex);
Atomics.store(queue, headIndex, nextHead);
console.log("Dequeued " + value + " from main thread");
return value;
}
setTimeout(() => {
enqueue(100);
enqueue(200);
dequeue();
}, 1000);
worker.onmessage = (event) => {
console.log("Message from worker:", event.data);
};
ì컀 ì€ë ë (worker.js):
// worker.js
let queue;
let headIndex = 0;
let tailIndex = 1;
let dataStartIndex = 2;
self.onmessage = (event) => {
const { buffer } = event.data;
queue = new Int32Array(buffer);
console.log("Worker received SharedArrayBuffer");
// Example: Enqueue from the worker thread
function enqueue(value) {
let tail = Atomics.load(queue, tailIndex);
const nextTail = (tail + 1) % (queue.length - dataStartIndex + dataStartIndex);
// Check if the queue is full (wrapping around)
let head = Atomics.load(queue, headIndex);
if (nextTail === head) {
console.log("Queue is full (worker).");
return;
}
Atomics.store(queue, dataStartIndex + tail, value);
Atomics.store(queue, tailIndex, nextTail);
console.log("Enqueued " + value + " from worker thread");
}
// Example: Dequeue from the worker thread (similar to enqueue)
function dequeue() {
let head = Atomics.load(queue, headIndex);
if (head === Atomics.load(queue, tailIndex)) {
console.log("Queue is empty (worker).");
return null;
}
const value = Atomics.load(queue, dataStartIndex + head);
const nextHead = (head + 1) % (queue.length - dataStartIndex + dataStartIndex);
Atomics.store(queue, headIndex, nextHead);
console.log("Dequeued " + value + " from worker thread");
return value;
}
setTimeout(() => {
enqueue(1);
enqueue(2);
dequeue();
}, 2000);
self.postMessage("Worker is ready");
};
ìŽ ìì ììë:
- í ë°ìŽí°ì head/tail í¬ìží°ë¥Œ ì ì¥íêž° ìíŽ `SharedArrayBuffer`ê° ìì±ë©ëë€.
- `Worker` ì€ë ëê° ìì±ëê³ `SharedArrayBuffer`ê° ì ë¬ë©ëë€.
- ììì ì°ì°(`Atomics.load`, `Atomics.store`)ì ì¬ì©íì¬ head ë° tail í¬ìží°ë¥Œ ìœê³ ì ë°ìŽížíì¬ ìì ì ììì±ì 볎ì¥í©ëë€.
- `enqueue` ë° `dequeue` íšìë íìì ìì륌 ì¶ê°íê³ ì ê±°íë©°, ê·žì ë°ëŒ head ë° tail í¬ìží°ë¥Œ ì ë°ìŽíží©ëë€. ê³µê°ì ì¬ì¬ì©íêž° ìíŽ ìí ë²íŒ(circular buffer) ì ê·Œë²ìŽ ì¬ì©ë©ëë€.
`SharedArrayBuffer` ë° `Atomics`ì ëí ì€ì ê³ ë €ì¬í:
- í¬êž° ì í: `SharedArrayBuffer`ìë í¬êž° ì íìŽ ììµëë€. íì ì í©í í¬êž°ë¥Œ 믞늬 ê²°ì íŽìŒ í©ëë€.
- ì€ë¥ ì²ëЬ: ìêž°ì¹ ìì 조걎ìŒë¡ ìžíŽ ì í늬ìŒìŽì ìŽ ì¶©ëíë ê²ì ë°©ì§íë €ë©Ž ì² ì í ì€ë¥ ì²ëŠ¬ê° ì€ìí©ëë€.
- ë©ëªšëЬ êŽëЬ: ë©ëªšëЬ ëìë êž°í ë©ëªšëЬ êŽë š 묞ì 륌 íŒíêž° ìíŽ ì ì€í ë©ëªšëЬ êŽëŠ¬ê° íìì ì ëë€.
- êµì°š ì¶ì² 격늬: `SharedArrayBuffer`ê° ì¬ë°ë¥Žê² ìëíë €ë©Ž ìë²ê° êµì°š ì¶ì² 격늬륌 íì±ííëë¡ ì¬ë°ë¥Žê² 구ì±ëìëì§ íìžíììì€. ì¬êž°ìë ìŒë°ì ìŒë¡ `Cross-Origin-Opener-Policy` ë° `Cross-Origin-Embedder-Policy` HTTP í€ë ì€ì ìŽ í¬íšë©ëë€.
3. ë©ìì§ í ì¬ì©íêž° (ì: Redis, RabbitMQ)
ëì± ê²¬ê³ íê³ íì¥ ê°ë¥í ì룚ì ì ìíŽìë Redisë RabbitMQì ê°ì ì ì© ë©ìì§ í ìì€í ì ì¬ì©íë ê²ì ê³ ë €íììì€. ìŽë¬í ìì€í ì ëŽì¥ë ì€ë ë ìì ì±, ììì±, ê·žëŠ¬ê³ ë©ìì§ ëŒì°í ë° ì°ì ìì ì§ì 곌 ê°ì ê³ êž êž°ë¥ì ì ê³µí©ëë€. ìŒë°ì ìŒë¡ ìë¡ ë€ë¥ž ìë¹ì€ ê°ì íµì (ë§ìŽí¬ë¡ìë¹ì€ ìí€í ì²)ì ì¬ì©ëì§ë§, ëšìŒ ì í늬ìŒìŽì ëŽìì 백귞ëŒìŽë ìì ì êŽëЬíë ë°ìë ì¬ì©í ì ììµëë€.
Redis ë° `ioredis` ëŒìŽëžë¬ëŠ¬ë¥Œ ì¬ì©í ìì :
const Redis = require('ioredis');
// Connect to Redis
const redis = new Redis();
const queueName = 'my_queue';
async function enqueue(message) {
await redis.lpush(queueName, JSON.stringify(message));
console.log(`Enqueued message: ${JSON.stringify(message)}`);
}
async function dequeue() {
const message = await redis.rpop(queueName);
if (message) {
const parsedMessage = JSON.parse(message);
console.log(`Dequeued message: ${JSON.stringify(parsedMessage)}`);
return parsedMessage;
} else {
console.log('Queue is empty.');
return null;
}
}
async function processQueue() {
while (true) {
const message = await dequeue();
if (message) {
// Process the message
console.log(`Processing message: ${JSON.stringify(message)}`);
} else {
// Wait for a short period before checking the queue again
await new Promise(resolve => setTimeout(resolve, 1000));
}
}
}
// Example usage
async function main() {
await enqueue({ task: 'process_data', data: { id: 123 } });
await enqueue({ task: 'send_email', data: { recipient: 'user@example.com' } });
processQueue(); // Start processing the queue in the background
}
main();
ìŽ ìì ììë:
- `ioredis` ëŒìŽëžë¬ëŠ¬ë¥Œ ì¬ì©íì¬ Redis ìë²ì ì°ê²°í©ëë€.
- `enqueue` íšìë `lpush`륌 ì¬ì©íì¬ íì ë©ìì§ë¥Œ ì¶ê°í©ëë€.
- `dequeue` íšìë `rpop`ì ì¬ì©íì¬ íìì ë©ìì§ë¥Œ ê²ìí©ëë€.
- `processQueue` íšìë íìì ë©ìì§ë¥Œ ê³ìíŽì ëííê³ ì²ëЬí©ëë€.
Redisë 늬ì€íž ì¡°ìì ìí ììì ì°ì°ì ì ê³µíë¯ë¡ 볞ì§ì ìŒë¡ ì€ë ë ìì í©ëë€. ì¬ë¬ íë¡ìžì€ë ì€ë ëê° ë°ìŽí° ìì ììŽ ìì íê² ë©ìì§ë¥Œ ìžííê³ ëíí ì ììµëë€.
ì¬ë°ë¥ž ì ê·Œë² ì ííêž°
ì€ë ë ìì í êŽëŠ¬ë¥Œ ìí ìµìì ì ê·Œë²ì í¹ì ì구ì¬í곌 ì ìœ ì¡°ê±Žì ë°ëŒ ë€ëŠ ëë€. ë€ì ìì륌 ê³ ë €íììì€:
- ë³µì¡ì±: 뮀í ì€ë ëšìŒ ì€ë ëë íë¡ìžì€ ëŽì Ʞ볞 ëìì±ì ìíŽ ë¹êµì ê°ëšíê² êµ¬íí ì ììµëë€. `SharedArrayBuffer`ì `Atomics`ë íšì¬ ë ë³µì¡íë¯ë¡ 죌ìíŽì ì¬ì©íŽìŒ í©ëë€. ë©ìì§ íë ê°ì¥ ëì ìì€ì ì¶ìí륌 ì ê³µíë©° ìŒë°ì ìŒë¡ ë³µì¡í ìë늬ì€ìì ì¬ì©íêž° ê°ì¥ ìœìµëë€.
- ì±ë¥: 뮀í ì€ë ì êž ë° ì êž íŽì ë¡ ìží ì€ë²í€ë륌 ë°ììíµëë€. `SharedArrayBuffer`ì `Atomics`ë ìŒë¶ ìë늬ì€ìì ë ëì ì±ë¥ì ì ê³µí ì ìì§ë§ ì ì€í ìµì íê° íìí©ëë€. ë©ìì§ íë ë€ížìí¬ ì§ì° ë° ì§ë ¬í/ìì§ë ¬í ì€ë²í€ë륌 ë°ììíµëë€.
- íì¥ì±: 뮀í ì€ì `SharedArrayBuffer`ë ìŒë°ì ìŒë¡ ëšìŒ íë¡ìžì€ë ëšžì ìŒë¡ ì íë©ëë€. ë©ìì§ íë ì¬ë¬ ëšžì ì ê±žì³ ìíì ìŒë¡ íì¥í ì ììµëë€.
- ììì±: 뮀í ì€ì `SharedArrayBuffer`ë ììì±ì ì ê³µíì§ ììµëë€. Redis ë° RabbitMQì ê°ì ë©ìì§ íë ììì± ìµì ì ì ê³µí©ëë€.
- ì 뢰ì±: ë©ìì§ íë ë©ìì§ íìž(acknowledgment) ë° ì¬ì ì¡ê³Œ ê°ì êž°ë¥ì ì ê³µíì¬ ìë¹ìê° ì€íšíëëŒë ë©ìì§ê° ìì€ëì§ ìëë¡ ë³Žì¥í©ëë€.
ëì í êŽëŠ¬ë¥Œ ìí ëªšë² ì¬ë¡
- ìê³ êµ¬ì ìµìí: 겜í©ì ìµìííêž° ìíŽ ì êž ë©ì»€ëìŠ(ì: 뮀í ì€) ëŽì ìœë륌 ê°ë¥í í ì§§ê³ íšìšì ìŒë¡ ì ì§íììì€.
- êµì°© ìí ë°©ì§: ë ìŽìì ì€ë ëê° ìë¡ë¥Œ 묎Ʞí êž°ë€ëŠ¬ë©° ì°šëšëë êµì°© ìí륌 ë°©ì§íêž° ìíŽ ì êž ì ëµì ì ì€íê² ì€ê³íììì€.
- ì°ìí ì€ë¥ ì²ëЬ: ìêž°ì¹ ìì ììžê° í ìì ì ë°©íŽíì§ ìëë¡ ê²¬ê³ í ì€ë¥ ì²ëЬ êž°ë¥ì 구ííììì€.
- í ì±ë¥ 몚ëí°ë§: í êžžìŽ, ì²ëЬ ìê° ë° ì€ë¥ìšì ì¶ì íì¬ ì ì¬ì ìž ë³ëª© íìì ìë³íê³ ì±ë¥ì ìµì ííììì€.
- ì ì í ìë£ êµ¬ì¡° ì¬ì©: ì í늬ìŒìŽì ìŽ í¹ì í ìì (ì: ì쪜 ëìì ìì ì¶ê° ëë ì ê±°)ì ì구íë 겜ì°, ìŽì€ ì¢ ë£ í(deque)ì ê°ì í¹ì ìë£ êµ¬ì¡° ì¬ì©ì ê³ ë €íììì€.
- ì² ì í í ì€íž: í 구íìŽ ì€ë ë ìì íê³ ê³Œë¶í ìíììë ì¬ë°ë¥Žê² ìëíëì§ íìžíêž° ìíŽ ëìì± í ì€ížë¥Œ í¬íší ì격í í ì€ížë¥Œ ìííììì€.
- ìœë 묞ìí: ì¬ì©ë ì êž ë©ì»€ëìŠê³Œ ëìì± ì ëµì í¬íšíì¬ ìœë륌 ëª ííê² ë¬žìííììì€.
êžë¡ë² ê³ ë €ì¬í
êžë¡ë² ì í늬ìŒìŽì ì ìí ëì í ìì€í ì ì€ê³í ë ë€ìì ê³ ë €íììì€:
- ìê°ë: íìì€í¬íì ì€ìŒì€ë§ ë©ì»€ëìŠìŽ ì¬ë¬ ìê°ëì ê±žì³ ì¬ë°ë¥Žê² ì²ëЬëëë¡ íììì€. íìì€í¬í ì ì¥ìë UTC륌 ì¬ì©íììì€.
- ë°ìŽí° ì§ìì±: ê°ë¥íë€ë©Ž ì§ì° ìê°ì ì€ìŽêž° ìíŽ íìí ì¬ì©ììê² ë ê°ê¹ìŽ ê³³ì ë°ìŽí°ë¥Œ ì ì¥íììì€. ì§ëЬì ìŒë¡ ë¶ì°ë ë©ìì§ í ì¬ì©ì ê³ ë €íììì€.
- ë€ížìí¬ ì§ì° ìê°: ë€ížìí¬ ìë³µ ìê°ì ìµìííëë¡ ìœë륌 ìµì ííììì€. íšìšì ìž ì§ë ¬í íì곌 ìì¶ êž°ì ì ì¬ì©íììì€.
- 묞ì ìžìœë©: í ìì€í ìŽ ë€ìí ìžìŽì ë°ìŽí°ë¥Œ ìì©í ì ìëë¡ êŽë²ìí 묞ì ìžìœë©ì ì§ìíëì§ íìžíììì€. UTF-8 ìžìœë©ì ì¬ì©íììì€.
- 묞íì 믌ê°ì±: ë©ìì§ íì곌 ì€ë¥ ë©ìì§ë¥Œ ì€ê³í ë 묞íì ì°šìŽë¥Œ ìŒëì ëììì€.
ê²°ë¡
ì€ë ë ìì í êŽëЬë ê²¬ê³ íê³ íì¥ ê°ë¥í ìë°ì€í¬ëŠœíž ì í늬ìŒìŽì ì 구ì¶íë ë° ì€ìí 잡멎ì ëë€. ëìì±ì ìŽë €ìì ìŽíŽíê³ ì ì í ëêž°í êž°ì ì ì¬ì©íšìŒë¡ìš ë°ìŽí° 묎결ì±ì 볎ì¥íê³ ê²œì ìí륌 ë°©ì§í ì ììµëë€. 뮀í ì€ë¥Œ ì¬ì©íë , `SharedArrayBuffer`ì íšê» ììì ì°ì°ì ì¬ì©íë , ëë ì ì© ë©ìì§ í ìì€í ì ì¬ì©íë , ì ì€í ê³í곌 ì² ì í í ì€ížê° ì±ê³µì íì ììì ëë€. ì í늬ìŒìŽì ì í¹ì ì구ì¬í곌 ë°°í¬ë êžë¡ë² 컚í ì€ížë¥Œ ê³ ë €íë ê²ì ìì§ ë§ììì€. ìë°ì€í¬ëŠœížê° ê³ì ë°ì íê³ ë ì êµí ëìì± ëªšëžì ì±ííšì ë°ëŒ, ìŽë¬í êž°ì ì ìµëíë ê²ì ê³ ì±ë¥ì ì 뢰í ì ìë ì í늬ìŒìŽì ì 구ì¶íë ë° ì ì ë ì€ìíŽì§ ê²ì ëë€.