TypedArray i TypeScript

TypedArray i TypeScript

Denne artikel forklarer TypedArray i TypeScript.

Vi vil forklare TypedArray i TypeScript, inklusive praktiske eksempler.

YouTube Video

TypedArray i TypeScript

TypedArray er en mekanisme til effektiv håndtering af binære data. Det er især nyttigt til lav-niveau binære operationer såsom store billeddata, netværksbyte-strømme og numeriske arrays til WebGL.

Sådan opretter du en ArrayBuffer

ArrayBuffer repræsenterer et område af bytes med fast længde. Først opretter du en buffer og tjekker dens størrelse og bytelængde.

1// Create an ArrayBuffer of 16 bytes
2const buffer: ArrayBuffer = new ArrayBuffer(16);
3console.log("buffer.byteLength:", buffer.byteLength); // 16
  • Denne kode opretter et tomt område på 16 byte. ArrayBuffer har ikke i sig selv læse-/skrivefunktioner, så du tilgår den gennem TypedArray eller DataView.

Typer af TypedArray

Der findes mange typer af TypedArray, såsom følgende. Disse varierer afhængigt af den datatype og størrelse, de håndterer.

TypedArray Datatype Bitlængde
Int8Array 8-bit heltal 8 bits
Uint8Array Usigneret 8-bit heltal 8 bits
Uint8ClampedArray Begrænset usigneret 8-bit heltal 8 bits
Int16Array 16-bit heltal 16 bits
Uint16Array Usigneret 16-bit heltal 16 bits
Int32Array 32-bit heltal 32 bits
Uint32Array Usigneret 32-bit heltal 32 bits
Float32Array 32-bit flydende-kommat tal 32 bits
Float64Array 64-bit flydende-kommat tal 64 bits

Basale TypedArrays (Uint8Array, Int16Array, Float32Array osv.)

TypedArray opretter et 'typed view' oven på en ArrayBuffer. Nedenfor er eksempler på oprettelse og brug af nogle typiske TypedArrays.

 1// Create a buffer and different typed views over it
 2const buf = new ArrayBuffer(8); // 8 bytes
 3
 4// Create views
 5const u8 = new Uint8Array(buf);    // 8 x uint8
 6const i16 = new Int16Array(buf);   // 4 x int16 (since each int16 is 2 bytes)
 7const f32 = new Float32Array(buf); // 2 x float32 (4 bytes each)
 8
 9console.log("Uint8 length:", u8.length);
10console.log("Int16 length:", i16.length);
11console.log("Float32 length:", f32.length);
  • Ved at oprette flere views på den samme ArrayBuffer kan du læse og skrive den samme hukommelse i forskellige typer eller granulariteter. length af viewet er antallet af elementer, og byteLength er antallet af bytes.

Skrivning og læsning (byte-niveau operationer)

Når du skriver en værdi til en TypedArray, opdateres de tilsvarende bytes i hukommelsen. Du kan se ændringerne, når du læser den samme buffer med et andet view.

 1// Demonstrate writing via one view and reading via another
 2const buffer2 = new ArrayBuffer(4);
 3const u8view = new Uint8Array(buffer2);
 4const u32view = new Uint32Array(buffer2);
 5
 6u8view[0] = 0x78;
 7u8view[1] = 0x56;
 8u8view[2] = 0x34;
 9u8view[3] = 0x12;
10
11console.log("Uint8 bytes:", Array.from(u8view)); // [120, 86, 52, 18]
12console.log("Uint32 value (platform endianness):", u32view[0]); // value depends on endianness
  • I dette eksempel skriver vi en bytesekvens og læser derefter det samme område som et 32-bit heltal. Bemærk, at output afhænger af endianness i eksekveringsmiljøet.

Endianness (byte-orden) og DataView

DataView er nyttigt, hvis du vil kontrollere miljøafhængige endianness-problemer. DataView giver dig mulighed for at angive endianness ved læsning og skrivning.

 1// Use DataView to read/write with explicit endianness control
 2const b = new ArrayBuffer(4);
 3const dv = new DataView(b);
 4
 5// write little-endian 32-bit integer
 6dv.setUint32(0, 0x12345678, true);
 7
 8// read as little-endian and big-endian
 9const little = dv.getUint32(0, true);
10const big = dv.getUint32(0, false);
11
12console.log("little-endian read:", little.toString(16)); // "12345678"
13console.log("big-endian read:", big.toString(16));       // different value
  • DataView er en praktisk mekanisme til detaljeret læsning og skrivning af bytes. Den understøtter en række typer såsom signed/unsigned heltal og flydende tal, og giver dig mulighed for eksplicit at angive endianness (byte-orden), hvilket er meget nyttigt ved implementering af binære protokoller.

Forskel mellem subarray og slice

subarray på en TypedArray returnerer et view, der deler den originale buffer, mens slice returnerer en ny kopi. Ydelse og bivirkninger varierer afhængigt af, hvilken du bruger.

1const base = new Uint8Array([1, 2, 3, 4, 5]);
2
3const shared = base.subarray(1, 4); // shares underlying buffer
4const copied = base.slice(1, 4);    // copies data
5
6shared[0] = 99;
7console.log("base after shared modification:", base); // shows change
8console.log("copied remains:", copied);              // unaffected
  • Hvis du ændrer den delte visning, vil den oprindelige array også ændre sig, hvilket kan forårsage utilsigtede bivirkninger. Hvis du ønsker at bevare den oprindelige array sikkert, kan du på forhånd oprette en kopi ved hjælp af slice().

Kopiering af buffers og typekonvertering (konvertering mellem TypedArrays)

Vi forklarer, hvordan man kopierer data mellem TypedArrays og indsætter dele med set-metoden.

 1// Copy and convert between typed arrays
 2const src = new Float32Array([1.5, 2.5, 3.5]);
 3const dst = new Uint16Array(src.length);
 4
 5// Convert by mapping (explicit conversion)
 6for (let i = 0; i < src.length; i++) {
 7  dst[i] = Math.round(src[i]); // simple conversion rule
 8}
 9console.log("converted dst:", Array.from(dst)); // [2, 2, 4]
10
11// Using set to copy bytes (requires compatible underlying buffer or same element type)
12const src2 = new Uint8Array([10, 20, 30]);
13const dst2 = new Uint8Array(6);
14dst2.set(src2, 2); // copy src2 into dst2 starting at index 2
15console.log("dst2 after set:", Array.from(dst2)); // [0,0,10,20,30,0]
  • Hvis elementtyperne er forskellige, skal du konvertere værdierne (f.eks. afrunding eller kontrol af værdier), i stedet for bare at kopiere. set tillader hurtig kopiering mellem TypedArrays af samme elementtype.

Praktisk eksempel: En parser til binær protokol (simpel implementering)

Her introducerer vi et simpelt parser-eksempel, der læser binære data i fast format bestående af 1 byte type, 2 byte datalængde og en efterfølgende payload.

 1// Simple binary message parser:
 2// format: [type: uint8][length: uint16 BE][payload: length bytes]
 3function parseMessages(buffer: ArrayBuffer) {
 4  const dv = new DataView(buffer);
 5  let offset = 0;
 6  const messages: { type: number; payload: Uint8Array }[] = [];
 7
 8  while (offset + 3 <= dv.byteLength) {
 9    const type = dv.getUint8(offset);
10    const length = dv.getUint16(offset + 1, false); // big-endian
11    offset += 3;
12    if (offset + length > dv.byteLength) break; // truncated
13    const payload = new Uint8Array(buffer, offset, length);
14    messages.push({ type, payload });
15    offset += length;
16  }
17
18  return messages;
19}
20
21// Example usage
22const buf = new ArrayBuffer(1 + 2 + 3 + 1 + 2 + 2); // two messages
23const dv = new DataView(buf);
24let off = 0;
25// first message: type=1, length=3, payload=[1,2,3]
26dv.setUint8(off, 1); dv.setUint16(off + 1, 3, false); off += 3;
27new Uint8Array(buf, off, 3).set([1, 2, 3]); off += 3;
28// second message: type=2, length=2, payload=[9,8]
29dv.setUint8(off, 2); dv.setUint16(off + 1, 2, false); off += 3;
30new Uint8Array(buf, off, 2).set([9, 8]);
31
32console.log(parseMessages(buf));
  • I dette eksempel læses headeren med DataView, og nyttelast-segmentet oprettes med Uint8Array. Endianness og tjek af buffer-længde er vigtigt.

Web API og TypedArray (Eksempel: hentning af binære data)

Dette er et typisk eksempel på håndtering af en ArrayBuffer hentet fra et netværkskald ved hjælp af TypedArray.

 1// Example of fetching binary and mapping to typed array
 2async function fetchBinary(url: string) {
 3  const res = await fetch(url);
 4  const ab = await res.arrayBuffer();
 5  const view = new Uint8Array(ab);
 6  // process view...
 7  console.log("received bytes:", view.length);
 8  return view;
 9}
10
11// Usage (call in async context)
12// fetchBinary("/path/to/file.bin");
  • Du kan direkte give en ArrayBuffer hentet med Response.arrayBuffer() til en TypedArray. Den bruges til billeder, lyd eller brugerdefinerede binære protokoller.

Ydelsestips og almindelige faldgruber

Her er nogle 'ydelsestips' og 'almindelige faldgruber', som er nyttige at kende, når du bruger TypedArrays:.

  • Undgå unødig kopiering For at behandle store datamængder effektivt kan du mindske unødvendig kopiering ved at oprette delvise views med subarray eller dele den samme ArrayBuffer i flere views.

  • Vær opmærksom på endianness For netværkskommunikation eller filformater er rækkefølgen af data (byte-orden) ofte specificeret. Ved at bruge DataView kan du eksplicit angive endianness ved læsning og skrivning og undgå utilsigtet fejlfortolkning.

  • Vær opmærksom på værdigrænser for hver type For eksempel kan Uint8 kun repræsentere værdier fra 0 til 255. Hvis du indtaster en negativ værdi, kan afkortning eller overløb forekomme, så du bør definere konverteringsregler efter behov.

  • Tag hensyn til belastning af garbage collection Ofte at genskabe store ArrayBuffers øger byrden for hukommelsesstyring. I præstationskritiske situationer kan du overveje at designe koden, så eksisterende buffere genbruges så meget som muligt.

Sammendrag

TypedArray er en mekanisme til hurtig og effektiv håndtering af binære data. Ved at kombinere ArrayBuffer, der reserverer et byteområde med fast længde, med TypedArray eller DataView, som læser og skriver indholdet med specifikke typer, kan du udføre fleksible binære operationer. Afhængig af dine anvendelsestilfælde kan du vælge mellem at bruge subarray/slice eller DataView og designe din implementering med opmærksomhed på endianness og kopier.

Du kan følge med i ovenstående artikel ved hjælp af Visual Studio Code på vores YouTube-kanal. Husk også at tjekke YouTube-kanalen.

YouTube Video