Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updated Documentation for worker import URL #424

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 17 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ Uses web workers in the browser, `worker_threads` in node 12+ and [`tiny-worker`

### Features

* First-class support for **async functions** & **observables**
* Write code once, run it **on all platforms**
* Manage bulk task executions with **thread pools**
* Use **require()** and **import**/**export** in workers
* Works great with **webpack**
- First-class support for **async functions** & **observables**
- Write code once, run it **on all platforms**
- Manage bulk task executions with **thread pools**
- Use **require()** and **import**/**export** in workers
- Works great with **webpack**

### Version 0.x

Expand All @@ -31,7 +31,7 @@ You can find the old version 0.12 of threads.js on the [`v0` branch](https://git
npm install threads tiny-worker
```

*You only need to install the `tiny-worker` package to support node.js < 12. It's an optional dependency and used as a fallback if `worker_threads` are not available.*
_You only need to install the `tiny-worker` package to support node.js < 12. It's an optional dependency and used as a fallback if `worker_threads` are not available._

## Platform support

Expand All @@ -42,7 +42,7 @@ npm install threads tiny-worker

Running code using threads.js in node works out of the box.

Note that we wrap the native `Worker`, so `new Worker("./foo/bar")` will resolve the path relative to the module that calls it, not relative to the current working directory.
Note that we wrap the native `Worker`, so `new Worker(new URL("./foo/bar", import.meta.url))` will resolve the path relative to the module that calls it, not relative to the current working directory.

That aligns it with the behavior when bundling the code with webpack or parcel.

Expand Down Expand Up @@ -147,26 +147,26 @@ Everything else should work out of the box.

```js
// master.js
import { spawn, Thread, Worker } from "threads"
import { spawn, Thread, Worker } from "threads";

const auth = await spawn(new Worker("./workers/auth"))
const hashed = await auth.hashPassword("Super secret password", "1234")
const auth = await spawn(new Worker(new URL("./workers/auth", import.meta.url)));
const hashed = await auth.hashPassword("Super secret password", "1234");
Comment on lines +152 to +153

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's up with the semicolons?


console.log("Hashed password:", hashed)
console.log("Hashed password:", hashed);

await Thread.terminate(auth)
await Thread.terminate(auth);
```

```js
// workers/auth.js
import sha256 from "js-sha256"
import { expose } from "threads/worker"
import sha256 from "js-sha256";
import { expose } from "threads/worker";

expose({
hashPassword(password, salt) {
return sha256(password + salt)
}
})
return sha256(password + salt);
},
});
Comment on lines +168 to +169

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And the dangling comma?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

those are my prettifyjs settings...

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rest of the code does not have semicolons, except for /docs/_includes/scripts/article.js
and src/index.ts that do and don't 😃

export { registerSerializer } from "./common"
export * from "./master/index"
export { expose } from "./worker/index"
export { DefaultSerializer, JsonSerializable, Serializer, SerializerImplementation } from "./serializers"
export { Transfer, TransferDescriptor } from "./transferable"
export { ExposedToThreadType as ExposedAs } from "./master/spawn";
export { QueuedTask } from "./master/pool";

```

### spawn()
Expand Down
86 changes: 43 additions & 43 deletions docs/usage-advanced.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,48 +11,49 @@ aside:

## Transferable objects

Use `Transfer()` to mark [transferable objects](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers#Passing_data_by_transferring_ownership_(transferable_objects)) like ArrayBuffers to be transferred to the receiving thread. It can speed up your code a lot if you are working with big pieces of binary data.
Use `Transfer()` to mark [transferable objects](<https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers#Passing_data_by_transferring_ownership_(transferable_objects)>) like ArrayBuffers to be transferred to the receiving thread. It can speed up your code a lot if you are working with big pieces of binary data.

`Transfer()` comes in two flavors:
* `Transfer(myBuffer: Transferable)`
* `Transfer(arrayOrObjectContainingBuffers: any, [myBuffer]: Transferable[])`

- `Transfer(myBuffer: Transferable)`
- `Transfer(arrayOrObjectContainingBuffers: any, [myBuffer]: Transferable[])`

Use it when calling a thread function or returning from a thread function:

```js
// master.js
import { spawn, Transfer, Worker } from "threads"
import { spawn, Transfer, Worker } from "threads";

const xorBuffer = await spawn(new Worker("./workers/arraybuffer-xor"))
const resultBuffer = await xorBuffer(Transfer(testData), 127)
const xorBuffer = await spawn(new Worker(new URL("./workers/arraybuffer-xor", import.meta.url)));
const resultBuffer = await xorBuffer(Transfer(testData), 127);
```

```js
// workers/arraybuffer-xor.js
import { expose, Transfer } from "threads/worker"
import { expose, Transfer } from "threads/worker";

expose(function xorBuffer(buffer, value) {
const view = new Uint8Array(buffer)
view.forEach((byte, offset) => view.set([byte ^ value], offset))
return Transfer(buffer)
})
const view = new Uint8Array(buffer);
view.forEach((byte, offset) => view.set([byte ^ value], offset));
return Transfer(buffer);
});
```

Without `Transfer()` the buffers would be copied on every call and every return. Using `Transfer()` their ownership is transferred to the other thread instead only, to make sure it is accessible in a thread-safe way. This is a much faster operation.

You can use transferable objects with observables, too.

```js
import { expose, Observable, Transfer } from "threads/worker"
import { DataSource } from "./my-data-source"
import { expose, Observable, Transfer } from "threads/worker";
import { DataSource } from "./my-data-source";

expose(function streamBuffers() {
return new Observable(observer => {
const datasource = new DataSource()
datasource.on("data", arrayBuffer => observer.next(Transfer(arrayBuffer)))
return () => datasource.close()
})
})
return new Observable((observer) => {
const datasource = new DataSource();
datasource.on("data", (arrayBuffer) => observer.next(Transfer(arrayBuffer)));
return () => datasource.close();
});
});
```

## Task queue
Expand All @@ -66,17 +67,17 @@ Threads.js does not provide a distinct task queue implementation, but it comes w
Every spawned thread emits events during its lifetime that you can subscribe to. This can be useful for debugging.

```js
import { spawn, Thread, Worker } from "threads"
import { spawn, Thread, Worker } from "threads";

const myThread = await spawn(new Worker("./mythread"))
const myThread = await spawn(new Worker(new URL("./mythread", import.meta.url)));

Thread.events(myThread).subscribe(event => console.log("Thread event:", event))
Thread.events(myThread).subscribe((event) => console.log("Thread event:", event));
```

There is a specialized function to subscribe only to thread error events:

```js
Thread.errors(myThread).subscribe(error => console.log("Thread error:", error))
Thread.errors(myThread).subscribe((error) => console.log("Thread error:", error));
```

## Custom message serializers
Expand All @@ -88,18 +89,18 @@ You can however define and register custom serializers to provide support for pa
First you need to implement your serializer. Fortunately, this is pretty straight-forward.

```typescript
import { SerializerImplementation } from "threads"
import { SerializerImplementation } from "threads";

interface SerializedMyClass {
__type: "$$MyClass"
state: string
__type: "$$MyClass";
state: string;
}

class MyClass {
state: string
state: string;

constructor(initialState: string) {
this.state = initialState
this.state = initialState;
}

doStuff() {
Expand All @@ -109,58 +110,57 @@ class MyClass {
serialize(): SerializedMyClass {
return {
__type: "$$MyClass",
state: this.state
}
state: this.state,
};
}

static deserialize(message: SerializedMyClass) {
return new MyClass(message.state)
return new MyClass(message.state);
}
}

const MySerializer: SerializerImplementation = {
deserialize(message, defaultHandler) {
if (message && message.__type === "$$MyClass") {
return MyClass.deserialize(message as any)
return MyClass.deserialize(message as any);
} else {
return defaultHandler(message)
return defaultHandler(message);
}
},
serialize(thing, defaultHandler) {
if (thing instanceof MyClass) {
return thing.serialize()
return thing.serialize();
} else {
return defaultHandler(thing)
return defaultHandler(thing);
}
}
}
},
};
```

Finally, register your serializer in both the main thread and the worker. Register it early, before you `spawn()` or `expose()` anything.

```typescript
import { registerSerializer } from "threads"
import { registerSerializer } from "threads";
// also exported from the worker sub-module:
// import { registerSerializer } from "threads/worker"

registerSerializer(MySerializer)
registerSerializer(MySerializer);
```

You can also register multiple serializers. Just call `registerSerializer()` multiple times – make sure to register the same serializers in the worker and main thread.

The registered serializers will then be chained. The serializer that was registered at last is invoked first. If it does not know how to serialize the data, it will call its fallback handler which is the second-to-last serializer and so forth.

```typescript
import { registerSerializer } from "threads"
import { registerSerializer } from "threads";

registerSerializer(SomeSerializer)
registerSerializer(AnotherSerializer)
registerSerializer(SomeSerializer);
registerSerializer(AnotherSerializer);

// threads.js will first try to use AnotherSerializer, will fall back to SomeSerializer,
// eventually falls back to passing the data as is if no serializer can handle it
```


## Debug logging

We are using the [`debug`](https://github.com/visionmedia/debug) package to provide opt-in debug logging. All the package's debug messages have a scope starting with `threads:`, with different sub-scopes:
Expand Down
Loading