Làm việc với ArrayBuffer và TypedArray trong JavaScript

Trong JavaScript, ArrayBuffer là đối tượng được sử dụng để đại diện cho một vùng nhớ đệm dữ liệu nhị phân thô với độ dài cố định. Đây là nền tảng quan trọng khi cần xử lý các tệp tin phức tạp như hình ảnh, âm thanh, video hoặc thực hiện các giao tiếp mạng hiệu suất cao.

Cấu trúc của ArrayBuffer và TypedArray

Một ArrayBuffer không cho phép thao tác trực tiếp trên nội dung của nó. Thay vào đó, bạn cần sử dụng một "view" (hướng nhìn) để đọc hoặc ghi dữ liệu. Các "view" phổ biến nhất là TypedArrays (mảng định kiểu), bao gồm các loại như:

  • Uint8Array: Mỗi phần tử là 1 byte không dấu (0-255).
  • Int32Array: Mỗi phần tử là 4 byte số nguyên có dấu.
  • Float64Array: Mỗi phần tử là 8 byte số thực phẩy động.

Khởi tạo và sử dụng vùng nhớ nhị phân

Để bắt đầu, chúng ta khởi tạo một vùng nhớ và gán một mảng định kiểu để quản lý nó:

// Cấp phát vùng nhớ 16 byte
const memoryBlock = new ArrayBuffer(16);

// Sử dụng Uint8Array để quản lý từng byte
const view8 = new Uint8Array(memoryBlock);
view8[0] = 42;
view8[1] = 255;

console.log(view8.length); // 16
console.log(memoryBlock.byteLength); // 16

Ứng dụng trong xử lý hình ảnh

Dữ liệu nhị phân thường được dùng để tạo hoặc thao tác với pixel ảnh. Ví dụ dưới đây minh họa cách chuyển đổi một mảng byte thành chuỗi Base64 để hiển thị ảnh:

function displayRawImage(dataArray) {
    const rawBuffer = new Uint8Array(dataArray);
    
    // Chuyển đổi dữ liệu nhị phân sang chuỗi ký tự
    let binaryString = "";
    rawBuffer.forEach(byte => {
        binaryString += String.fromCharCode(byte);
    });

    const base64Content = btoa(binaryString);
    const imgElement = new Image();
    imgElement.src = `data:image/png;base64,${base64Content}`;
    
    document.body.appendChild(imgElement);
}

// Giả lập dữ liệu pixel
const pixelData = [137, 80, 78, 71, 13, 10, 26, 10]; // PNG header
displayRawImage(pixelData);

Giao tiếp mạng với dữ liệu nhị phân

Khi làm việc với các API hiện đại như fetch, chúng ta có thể gửi và nhận dữ liệu dưới dạng ArrayBuffer để tối ưu hóa băng thông.

async function uploadBinaryData(url, data) {
    const buffer = new Uint8Array(data).buffer;

    try {
        const response = await fetch(url, {
            method: 'POST',
            headers: { 'Content-Type': 'application/octet-stream' },
            body: buffer
        });
        
        if (response.ok) {
            const resultBuffer = await response.arrayBuffer();
            const resultView = new Uint8Array(resultBuffer);
            console.log("Dữ liệu phản hồi:", resultView);
        }
    } catch (error) {
        console.error("Lỗi khi tải dữ liệu:", error);
    }
}

Thực thi thuật toán trên mảng định kiểu

Sử dụng TypedArray giúp cải thiện hiệu suất đáng kể cho các thuật toán tính toán vì dữ liệu được lưu trữ liên tục trong bộ nhớ. Dưới đây là ví dụ về thuật toán sắp xếp cơ bản trên mảng số nguyên 32-bit:

function performFastSort(typedArray) {
    const len = typedArray.length;
    for (let i = 0; i < len; i++) {
        for (let j = 0; j < len - i - 1; j++) {
            if (typedArray[j] > typedArray[j + 1]) {
                // Hoán vị giá trị
                let temp = typedArray[j];
                typedArray[j] = typedArray[j + 1];
                typedArray[j + 1] = temp;
            }
        }
    }
}

const numbers = new Int32Array([50, 10, 40, 20, 30]);
performFastSort(numbers);
console.log(numbers); // [10, 20, 30, 40, 50]

Mã hóa dữ liệu mức thấp

Bạn có thể thực hiện các phép toán bitwise trực tiếp trên Uint8Array để xử lý các tác vụ như mã hóa XOR đơn giản:

function xorTransform(buffer, key) {
    const view = new Uint8Array(buffer);
    for (let i = 0; i < view.length; i++) {
        view[i] = view[i] ^ key; // Phép toán XOR
    }
    return view;
}

const originalData = new Uint8Array([10, 20, 30, 40]);
const secretKey = 0xFF;

console.log("Dữ liệu gốc:", originalData);

// Mã hóa
const encrypted = xorTransform(originalData.buffer, secretKey);
console.log("Sau khi mã hóa:", new Uint8Array(encrypted.buffer));

// Giải mã (XOR lại lần nữa với cùng một key)
const decrypted = xorTransform(encrypted.buffer, secretKey);
console.log("Sau khi giải mã:", new Uint8Array(decrypted.buffer));

Chuyển đổi dữ liệu JSON sang Buffer

Trong một số trường hợp, việc chuyển đổi JSON sang định dạng nhị phân giúp tương thích với các giao thức điều khiển phần cứng hoặc tối ưu lưu trữ.

function jsonToBuffer(obj) {
    const str = JSON.stringify(obj);
    const encoder = new TextEncoder();
    return encoder.encode(str).buffer;
}

function bufferToJson(buffer) {
    const decoder = new TextDecoder();
    const str = decoder.decode(buffer);
    return JSON.parse(str);
}

const user = { id: 1, name: "Admin" };
const encodedBuffer = jsonToBuffer(user);
console.log("Buffer size:", encodedBuffer.byteLength);

const decodedUser = bufferToJson(encodedBuffer);
console.log("Đối tượng phục hồi:", decodedUser);

Thẻ: JavaScript arraybuffer typedarray binary-data web-api

Đăng vào ngày 26 tháng 7 lúc 08:27