跳至主要内容

工作线程

Deno 支持 Web Worker API.

工作线程可用于在多个线程上运行代码。每个 Worker 实例都在单独的线程上运行,专门用于该工作线程。

目前 Deno 只支持 module 类型的 worker;因此在创建新 worker 时,必须传递 type: "module" 选项。

在主 worker 中使用相对模块说明符仅在 CLI 上传递 --location <href> 时才受支持。这对于可移植性来说并不推荐。您可以改为使用 URL 构造函数和 import.meta.url 来轻松创建附近脚本的说明符。但是,专用 worker 默认情况下具有位置和此功能。

// Good
new Worker(import.meta.resolve("./worker.js"), { type: "module" });

// Bad
new Worker(import.meta.resolve("./worker.js"));
new Worker(import.meta.resolve("./worker.js"), { type: "classic" });
new Worker("./worker.js", { type: "module" });

与常规模块一样,您可以在 worker 模块中使用顶层 await。但是,您应该注意始终在第一个 await 之前注册消息处理程序,因为否则可能会丢失消息。这不是 Deno 中的错误,只是功能的不幸交互,它也发生在所有支持模块 worker 的浏览器中。

import { delay } from "https://deno.land/std@0.220.0/async/delay.ts";

// First await: waits for a second, then continues running the module.
await delay(1000);

// The message handler is only set after that 1s delay, so some of the messages
// that reached the worker during that second might have been fired when no
// handler was registered.
self.onmessage = (evt) => {
console.log(evt.data);
};

实例化权限

创建新的 Worker 实例类似于动态导入;因此 Deno 需要此操作的适当权限。

对于使用本地模块的 worker;需要 --allow-read 权限

main.ts

new Worker(import.meta.resolve("./worker.ts"), { type: "module" });

worker.ts

console.log("hello world");
self.close();
$ deno run main.ts
error: Uncaught PermissionDenied: read access to "./worker.ts", run again with the --allow-read flag

$ deno run --allow-read main.ts
hello world

对于使用远程模块的 worker;需要 --allow-net 权限

main.ts

new Worker("https://example.com/worker.ts", { type: "module" });

worker.ts (位于 https://example.com/worker.ts)

console.log("hello world");
self.close();
$ deno run main.ts
error: Uncaught PermissionDenied: net access to "https://example.com/worker.ts", run again with the --allow-net flag

$ deno run --allow-net main.ts
hello world

在 worker 中使用 Deno

从 v1.22 开始,Deno 命名空间默认在 worker 范围内可用。要在早期版本中启用命名空间,请在创建新 worker 时传递 deno: { namespace: true }

main.js

const worker = new Worker(import.meta.resolve("./worker.js"), {
type: "module",
});

worker.postMessage({ filename: "./log.txt" });

worker.js

self.onmessage = async (e) => {
const { filename } = e.data;
const text = await Deno.readTextFile(filename);
console.log(text);
self.close();
};

log.txt

hello world
$ deno run --allow-read main.js
hello world

从 v1.23 开始,Deno.exit() 不再使用提供的退出代码退出进程。相反,它是 self.close() 的别名,这只会导致 worker 关闭。这与 Web 平台更好地一致,因为浏览器中没有办法让 worker 关闭页面。

指定 worker 权限

这是一个不稳定的 Deno 功能。了解更多关于 不稳定功能

worker 可用的权限类似于 CLI 权限标志,这意味着在那里启用的每个权限都可以在 Worker API 级别禁用。您可以找到每个权限选项的更详细描述 这里

默认情况下,worker 将继承创建它的线程的权限,但是为了允许用户限制此 worker 的访问权限,我们在 worker API 中提供了 deno.permissions 选项。

  • 对于支持细粒度访问的权限,您可以传入 worker 将访问的所需资源列表,对于只有开/关选项的权限,您可以分别传入 true/false。

    const worker = new Worker(import.meta.resolve("./worker.js"), {
    type: "module",
    deno: {
    permissions: {
    net: [
    "deno.land",
    ],
    read: [
    new URL("./file_1.txt", import.meta.url),
    new URL("./file_2.txt", import.meta.url),
    ],
    write: false,
    },
    },
    });
  • 细粒度访问权限接收绝对和相对路径作为参数,但请注意,相对路径将相对于实例化 worker 的文件解析,而不是 worker 文件当前所在的路径。

    const worker = new Worker(
    new URL("./worker/worker.js", import.meta.url).href,
    {
    type: "module",
    deno: {
    permissions: {
    read: [
    "/home/user/Documents/deno/worker/file_1.txt",
    "./worker/file_2.txt",
    ],
    },
    },
    },
    );
  • deno.permissions 及其子项都支持 "inherit" 选项,这意味着它将借用其父权限。

    // This worker will inherit its parent permissions
    const worker = new Worker(import.meta.resolve("./worker.js"), {
    type: "module",
    deno: {
    permissions: "inherit",
    },
    });
    // This worker will inherit only the net permissions of its parent
    const worker = new Worker(import.meta.resolve("./worker.js"), {
    type: "module",
    deno: {
    permissions: {
    env: false,
    hrtime: false,
    net: "inherit",
    ffi: false,
    read: false,
    run: false,
    write: false,
    },
    },
    });
  • 如果不指定deno.permissions选项或其子选项,则工作线程将默认继承权限。

    // This worker will inherit its parent permissions
    const worker = new Worker(import.meta.resolve("./worker.js"), {
    type: "module",
    });
    // This worker will inherit all the permissions of its parent BUT net
    const worker = new Worker(import.meta.resolve("./worker.js"), {
    type: "module",
    deno: {
    permissions: {
    net: false,
    },
    },
    });
  • 您可以通过将"none"传递给deno.permissions选项来完全禁用工作线程的权限。

    // This worker will not have any permissions enabled
    const worker = new Worker(import.meta.resolve("./worker.js"), {
    type: "module",
    deno: {
    permissions: "none",
    },
    });