TypedArray i TypeScript

TypedArray i TypeScript

Denne artikkelen forklarer TypedArray i TypeScript.

Vi skal forklare TypedArray i TypeScript, inkludert praktiske eksempler.

YouTube Video

TypedArray i TypeScript

TypedArray er en mekanisme for effektiv håndtering av binærdata. Det er spesielt nyttig for lavnivå binæroperasjoner som store bildedata, nettverksbytestømmer og numeriske matriser for WebGL.

Hvordan opprette en ArrayBuffer

ArrayBuffer representerer et område av byte med fast lengde. Først oppretter du en buffer og sjekker størrelsen og bytelengden.

1// Create an ArrayBuffer of 16 bytes
2const buffer: ArrayBuffer = new ArrayBuffer(16);
3console.log("buffer.byteLength:", buffer.byteLength); // 16
  • Denne koden oppretter et tomt område på 16 byte. ArrayBuffer har ikke egne lese/skriv-funksjoner, så du må aksessere den gjennom TypedArray eller DataView.

Typer av TypedArray

Det finnes mange typer TypedArray, som for eksempel følgende. Disse varierer avhengig av datatypen og størrelsen de håndterer.

TypedArray Datatype Bitstørrelse
Int8Array 8-bit heltall 8 biter
Uint8Array Uten fortegn 8-bit heltall 8 biter
Uint8ClampedArray Begrenset uten fortegn 8-bit heltall 8 biter
Int16Array 16-bit heltall 16 biter
Uint16Array Uten fortegn 16-bit heltall 16 biter
Int32Array 32-bit heltall 32 biter
Uint32Array Uten fortegn 32-bit heltall 32 biter
Float32Array 32-bits flyttall 32 biter
Float64Array 64-bits flyttall 64 biter

Grunnleggende TypedArrays (Uint8Array, Int16Array, Float32Array, osv.)

TypedArray oppretter en 'typet visning' på toppen av en ArrayBuffer. Her er eksempler på hvordan man oppretter og bruker noen 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 å lage flere visninger på samme ArrayBuffer kan du lese og skrive den samme minnet med forskjellige typer eller granulariteter. length for visningen er antall elementer, og byteLength er antall byte.

Skriving og lesing (byte-nivå operasjoner)

Når du skriver en verdi til en TypedArray, blir de tilsvarende bytene i minnet oppdatert. Du kan se endringene når du leser den samme bufferen med en annen visning.

 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 eksemplet skriver vi en bytesevens og leser så det samme området som et 32-bits heltall. Merk at utdataene avhenger av endianness i kjøringsmiljøet.

Endianness (byte-rekkefølge) og DataView

DataView er nyttig hvis du vil kontrollere miljøavhengige problemer med endianness. DataView lar deg spesifisere sluttianitet (endianness) når du leser og skriver.

 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 for detaljert lesing og skriving av byte. Den støtter ulike typer, som signerte og usignerte heltall samt flyttall, og lar deg eksplisitt spesifisere endianness (byte-rekkefølge), noe som er svært nyttig når du implementerer binære protokoller.

Forskjell mellom subarray og slice

subarray av en TypedArray returnerer en visning som deler den opprinnelige bufferen, mens slice returnerer en ny kopi. Ytelse og bivirkninger varierer avhengig av hvilken du bruker.

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 endrer den delte visningen, vil den opprinnelige matrisen også endres, noe som kan føre til utilsiktede bivirkninger. Hvis du vil bevare den opprinnelige matrisen trygt, kan du opprette en kopi på forhånd ved å bruke slice().

Kopiering av buffere og typekonvertering (konvertering mellom TypedArrays)

Vi forklarer hvordan du kopierer data mellom TypedArrays og hvordan du limer inn deler ved hjelp av 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 elementtypene er forskjellige, må du konvertere verdiene, for eksempel ved avrunding eller områdekontroll, i stedet for bare å kopiere. set gjør det mulig å raskt kopiere mellom TypedArrays av samme elementtype.

Praktisk eksempel: En binær protokollparser (enkel implementasjon)

Her introduserer vi et enkelt parser-eksempel som leser binærdata med fast format, bestående av en 1-byte type, 2-byte datalengde, og en påfø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 eksemplet leses headeren ved hjelp av DataView, og nyttelast-delen opprettes med Uint8Array. Endianness og bufferlengdekontroll er viktig.

Web-API og TypedArray (Eksempel: hente binærdata)

Dette er et typisk eksempel på å håndtere en ArrayBuffer hentet fra en nettverksforespørsel ved hjelp av 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 sende ArrayBuffer oppnådd med Response.arrayBuffer() direkte til en TypedArray. Det brukes for bilder, lyd eller egendefinerte binære protokoller.

Ytelsestips og vanlige fallgruver

Her er noen 'ytelsestips' og 'vanlige fallgruver' som det er nyttig å kjenne til når du bruker TypedArrays:.

  • Unngå unødvendig kopiering For å håndtere store datamengder effektivt, kan du redusere unødvendig kopiering ved å lage delvisninger med subarray eller dele samme ArrayBuffer på tvers av flere visninger.

  • Vær oppmerksom på endianness For nettverkskommunikasjon eller filformater er rekkefølgen på dataene (byterekkefølge) ofte spesifisert. Ved å bruke DataView kan du eksplisitt angi endianness ved lesing og skriving, og dermed unngå feil tolkning.

  • Vær oppmerksom på verdiområdet for hver type For eksempel kan Uint8 bare representere verdier fra 0 til 255. Hvis du oppgir en negativ verdi, kan det oppstå avkutting eller verdi-overløp, så du bør definere konverteringsregler etter behov.

  • Vurder belastningen på søppelinnsamling (garbage collection) Hyppig gjenskaping av store ArrayBuffer-objekter øker belastningen på minnehåndteringen. I ytelseskritiske situasjoner kan det være lurt å utforme koden slik at eksisterende buffere gjenbrukes så mye som mulig.

Sammendrag

TypedArray er en mekanisme for rask og effektiv håndtering av binærdata. Ved å kombinere ArrayBuffer, som reserverer et byteområde med fast lengde, med TypedArray eller DataView, som leser og skriver innholdet med bestemte typer, kan du utføre fleksible binæroperasjoner. Avhengig av bruken din kan du velge mellom å bruke subarray/slice eller DataView, og utforme implementasjonen din med hensyn til endianness og kopier.

Du kan følge med på artikkelen ovenfor ved å bruke Visual Studio Code på vår YouTube-kanal. Vennligst sjekk ut YouTube-kanalen.

YouTube Video