# 数组示例

展示了如何在 WebAssembly 或 JavaScript 中创建的数组之间交换和操作数组。

# 内容

  • 使用加载器和完整运行时来处理托管对象。
  • 在 WebAssembly 中创建数组并在 JavaScript 中使用它们。
  • 在 JavaScript 中创建数组并在 WebAssembly 中使用它们。
  • 同时使用数组的副本和实时视图。
  • 在已知数组长度的情况下执行 `unchecked` 访问。
  • 外部固定对象以防止过早垃圾回收。

# 示例

#!optimize=speed&runtime=default&exportRuntime
/** Creates a new array and returns it to JavaScript. */
export function createArray(length: i32): Int32Array {
  return new Int32Array(length)
}

/** Randomizes the specified array's values. */
export function randomizeArray(arr: Int32Array): void {
  for (let i = 0, k = arr.length; i < k; ++i) {
    let value = i32((Math.random() * 2.0 - 1.0) * i32.MAX_VALUE)
    unchecked(arr[i] = value)
  }
}

/** Computes the sum of an array's values and returns the sum to JavaScript. */
export function sumArray(arr: Int32Array): i32 {
  let total = 0
  for (let i = 0, k = arr.length; i < k; ++i) {
    total += unchecked(arr[i])
  }
  return total
}

// We'll need the unique Int32Array id when allocating one in JavaScript
export const Int32Array_ID = idof<Int32Array>()

#!html
<textarea id="output" style="width: 100%; height: 100%" readonly></textarea>
<script>
loader.instantiate(module_wasm).then(({ exports }) => {
  const output = document.getElementById('output')

  /** Logs a message to the textarea. */
  function log(message = '') {
    output.value += `${message}\n`
  }

  // A simple example using an array created in WebAssembly.
  function example1() {
    log('=== Example1 ===')

    // Obtain the necessary runtime helpers
    const { __pin, __unpin, __getArray } = exports

    // Create a new array in WebAssembly and get a reference to it. Note that
    // the array is not reachable from within WebAssembly, only externally, so
    // we should pin it to prevent it from becoming garbage collected too early.
    let arrayPtr = __pin(exports.createArray(5))
    log(`Array pointer: ${arrayPtr}`)

    // Log its elements to make sure these are zero
    log('Initial values: ' + __getArray(arrayPtr).join(', '))

    // Randomize the array in WebAssembly and log it again
    exports.randomizeArray(arrayPtr)
    log('Randomized values: ' + __getArray(arrayPtr).join(', '))

    // Compute the array values' sum and log it. This will overflow i32 range.
    let total = exports.sumArray(arrayPtr)
    log(`Sum (likely overflown): ${total}`)

    // We are done with the array, so __unpin it so it can become collected.
    __unpin(arrayPtr)

    log()
  }
  example1()

  // A slightly more advanced example allocating the array in JavaScript instead
  // of WebAssembly, and utilizing a live view to modify it in WebAssembly memory.
  function example2() {
    log('=== Example2 ===')

    // Obtain the necessary runtime helpers
    const { __pin, __unpin, __newArray, __getArray, __getArrayView } = exports

    // Create a new array, but this time in JavaScript. Note that the array is
    // again not reachable from within WebAssembly, only externally, so we
    // should pin it to prevent it from becoming garbage collected too early.
    let arrayPtr = __pin(__newArray(exports.Int32Array_ID, [
      3, 4, 5, 6, 7, 8, 9
    ]))
    log('Array pointer: ' + arrayPtr)

    // Log its elements to make sure these are the provided values
    log('Initial values: ' + __getArray(arrayPtr).join(', '))

    // Compute the array values' sum and log it
    let total = exports.sumArray(arrayPtr)
    log('Sum: ' + total)

    // Instead of copying, let's obtain a live view on the array and modify its
    // values right in WebAssembly memory.
    let view = __getArrayView(arrayPtr)
    view.reverse()

    // Log the array's elements, now reversed
    log('Reversed values: ' + __getArray(arrayPtr).join(', '))

    // We are done with the array, so __unpin it so it can become collected.
    __unpin(arrayPtr)

    log()
  }
  example2()
})
</script>

注意

此示例使用加载器来处理托管对象,因此需要将 `--exportRuntime` 设置为将运行时助手暴露给 JavaScript。

# 资源

有关使用加载器和运行时助手的更多信息,请参见 加载器垃圾回收文档 中的内容。