Dieser Inhalt wurde automatisch aus dem Englischen übersetzt, und kann Fehler enthalten. Erfahre mehr über dieses Experiment.

View in English Always switch to English

try_table: Wasm-Ausnahmebehandlungsanweisung

Die try_table Ausnahmebehandlungsanweisung ermöglicht es Ihnen, einen Codeblock zu testen, um festzustellen, ob eine Ausnahme geworfen wird, und diese Ausnahme in einer catch-Klausel zu behandeln.

Probieren Sie es aus

(module
  ;; Import error tag and console.log
  (tag $my_error (import "env" "my_error") (param i32))
  (import "env" "log" (func $log (param i32)))

  (func $try_and_catch (param $value i32)
    (block $handler (result i32)
      ;; In try_table block, catch thrown exception
      (try_table (catch $my_error $handler)
        (call $might_throw (local.get $value))
      )
      (return)
    )
    ;; Log value returned by handler block
    call $log
  )

  ;; Function that throws an error of type $my_error
  ;; when its parameter is less than 0
  (func $might_throw (param $value i32)
    (local.get $value)
    (i32.const 0)
    (i32.lt_s)
    (if
      (then
        ;; Throw exception with payload of 42
        (i32.const 42)
        (throw $my_error)
      )
    )
  )

  (export "try_and_catch" (func $try_and_catch))
)
// Define error tag in JS
const myErrorTag = new WebAssembly.Tag({ parameters: ["i32"] });

// Import error tag and console.log into the module
const env = {
  my_error: myErrorTag, // import the tag into the module
  log: console.log,
};

WebAssembly.instantiateStreaming(fetch("{%wasm-url%}"), { env }).then(
  // Negative value causes function to throw
  (result) => result.instance.exports.try_and_catch(-1),
);

Syntax

try_table blocktype catch* instruction*
try_table

Die try_table-Anweisung.

blocktype Optional

Gibt einen oder mehrere Parameter an, die in den try_table-Block übergeben werden und nach Ausführung des Blocks als Ergebniswert bereitgestellt werden.

catch*

Eine oder mehrere catch-Klauseln, die jeweils Kriterien für das Abfangen von Ausnahmen darstellen und angeben, zu welchem block als Ergebnis verzweigt wird. Jede Klausel kann eine der folgenden sein:

instruction*

Null oder mehr Anweisungen, die innerhalb des try-Blocks ausgeführt werden sollen.

Typ

[param*] -> [result*]
param*

Null oder mehr Parameterwerte, die vom try_table-Block verbraucht werden, wie im blocktype deklariert.

result*

Null oder mehr Ergebniswerte, die vom try_table-Block produziert werden, wie im blocktype deklariert.

Binärcodierung

Anweisung Binärformat
try_table 0x1f bt:blocktype n:u32 (ct:catch)^n instruction* 0x0b

Ein grundlegendes try_table mit einer einzelnen catch-Klausel:

wat
(try_table (catch $my_error $handler)
  ;; instructions ...
)

Würde wie folgt codiert:

0x1f 0x40 0x01 0x00 0x00 0x00 ...instructions binary... 0x0b

Beschreibung

Eine try_table-Anweisung, kombiniert mit catch-Klauseln, bildet das Wasm-Äquivalent einer JavaScript-try...catch-Anweisung. Die Anweisungen innerhalb des try_table-Blocks werden ausgeführt, und wenn eine Ausnahme geworfen wird, die von den verfügbaren catch-Klauseln abgefangen wird, verzweigt der Code zum angegebenen äußeren block, und die von der catch-Klausel produzierten Werte werden auf den Stapel gelegt.

Die unterschiedlichen catch-Klauseln verhalten sich wie folgt:

catch

Wenn eine Ausnahme mit einem passenden Tag geworfen wird, verzweigen Sie zum angegebenen block und legen die Nutzlastwerte auf den Stapel.

catch_all

Wenn irgendeine Ausnahme geworfen wird, verzweigen Sie zum angegebenen block, ohne etwas auf den Stapel zu legen.

catch_ref

Wenn eine Ausnahme mit einem passenden Tag geworfen wird, verzweigen Sie zum angegebenen block und legen die Nutzlastwerte sowie einen exnref-Wert, der die Ausnahme darstellt, auf den Stapel.

catch_all_ref

Wenn irgendeine Ausnahme geworfen wird, verzweigen Sie zum angegebenen block und legen einen exnref-Wert, der die Ausnahme darstellt, auf den Stapel.

Jede catch-Klausel, die zu einem äußeren block verzweigt, muss Werte produzieren, die dem Ergebnistyp dieses blocks entsprechen, wenn eine geworfene Ausnahme abgefangen wird.

Blocktype-Parameter

Die optionalen blocktypen Parameter werden in den try_table-Block übergeben und als Ergebniswert bereitgestellt, nachdem der Block ausgeführt wurde. Der Wert kann vor dem try_table-Block oder innerhalb davon angegeben werden. Zum Beispiel:

wat
;; Push an i32
i32.const 42

;; pops an i32 as the param
try_table (param i32)
  ;; The single i32 const 42 is still on the stack
end

Oder:

wat
try_table (result i32)
  ;; Push an i32
  i32.const 42

  ;; The end of the block pops the results
end

;; The result i32 is now available to be used here

Oder Sie können jede Kombination dieser Strukturen verwenden.

Beispiele

Umgang mit mehreren Ausnahmen

Dieses Beispiel zeigt, wie mehrere Ausnahmen in einer einzigen try_table-Struktur behandelt werden können.

JavaScript

In unserem Skript beginnen wir damit, eine Referenz zu einem <p>-Element zu erhalten, auf dem wir Ergebnisse ausgeben werden. Wir definieren dann zwei verschiedene Fehler-Tags, um einen Typfehler und einen Bereichsfehler zu repräsentieren, indem wir den WebAssembly.Tag()-Konstruktor verwenden.

js
const output = document.querySelector("p");

const typeErrorTag = new WebAssembly.Tag({ parameters: ["i32"] });
const rangeErrorTag = new WebAssembly.Tag({ parameters: ["i32", "i32"] });

Als nächstes kompilieren und instanziieren wir unser Wasm-Modul mit der Methode WebAssembly.instantiateStreaming(), indem wir die beiden Fehler-Tags importieren und eine Funktion, um Ergebnisse in das <p>-Element zu protokollieren.

Wir rufen die exportierte Wasm-try_multiple()-Funktion auf, die im WebAssembly-Instance-exports-Objekt verfügbar ist, mehrfach auf, indem wir ihr zwei verschiedene Parameter übergeben, um unterschiedliche Ausnahmen zu werfen, und schließlich einen Wert, der keine Ausnahme wirft.

js
async function init() {
  const { instance } = await WebAssembly.instantiateStreaming(
    fetch("{%wasm-url%}"),
    {
      env: {
        type_error: typeErrorTag,
        range_error: rangeErrorTag,
        log: (code) => {
          output.textContent += `Error code: ${code} | `;
        },
      },
    },
  );

  instance.exports.try_multiple(-1); // Throws type_error, logs 10
  instance.exports.try_multiple(101); // Throws range_error, logs 99
  instance.exports.try_multiple(50); // Doesn't throw
}

init();

Wasm

In unserem Wasm-Modul importieren wir zuerst unsere zwei Fehler-Tags und die Protokollfunktion. Dann erstellen wir eine Funktion namens $try_multiple, die zwei verschachtelte blocks hat, um $type_errors und $range_errors zu behandeln. In der Mitte der blocks befindet sich eine try_table-Struktur, die zwei catch-Klauseln enthält, um jeden Fehler abzufangen. Wir rufen dann die Funktion $might_throw auf, um zu sehen, ob sie Ausnahmen wirft:

  • Wenn ein $type_error geworfen wird, verzweigen wir zum $on_type_error-block und protokollieren den Nutzlastwert.
  • Wenn ein $range_error geworfen wird, verzweigen wir zum $on_range_error-block, lassen den ersten der beiden Nutzlastwerte fallen und protokollieren den zweiten, dann verlassen wir den block.
  • Wenn keine Ausnahme geworfen wird, verlassen wir einfach den block.

Die Funktion $might_throw selbst nimmt einen einzigen Parameter und überprüft dessen Wert. Wenn der Wert kleiner als 0 ist, wirft sie einen $type_error mit dem Fehlercode 10. Wenn der Wert größer als 100 ist, wirft sie einen $range_error mit dem Code 99.

wat
(module
  (tag $type_error (import "env" "type_error") (param i32))
  (tag $range_error (import "env" "range_error") (param i32 i32))  ;; carries two values
  (import "env" "log" (func $log (param i32)))

  (func $try_multiple (param $value i32)
    (block $on_type_error (result i32)
      (block $on_range_error (result i32 i32)
        (try_table
          (catch $type_error $on_type_error)
          (catch $range_error $on_range_error)
          (call $might_throw (local.get $value))
        )
        (return)  ;; no exception thrown
      )
      ;; $range_error was caught — stack has i32 i32
      (drop)                   ;; drop second payload value
      (call $log)              ;; log first payload value
      (return)
    )
    ;; $type_error was caught — stack has i32
    (call $log)                ;; log the payload
  )

  (func $might_throw (param $value i32)
    (local.get $value)
    (i32.const 0)
    (i32.lt_s)
    (if
      (then
        (i32.const 10)
        (throw $type_error)
      )
    )
    (local.get $value)
    (i32.const 100)
    (i32.gt_s)
    (if
      (then
        (i32.const 99)
        (i32.const 100)
        (throw $range_error)
      )
    )
  )

  (export "try_multiple" (func $try_multiple))
)

Ergebnis

Wir rufen die try_multiple()-Funktion dreimal auf. Das erste Mal wird ein $type_error geworfen, daher wird der Fehlercode 10 protokolliert. Das zweite Mal wird ein $range_error geworfen, daher wird der Fehlercode 99 protokolliert. Das dritte Mal wird keine Ausnahme geworfen.

Siehe auch