简体   繁体   中英

Can not clone object to web worker

<!DOCTYPE html>
<html>

<body>
  <button type="button" onclick='UseLocalFontsButton()'>Click Me!</button>
  <script>

    async function UseLocalFontsButton() {
      try {
        const array = await self.queryLocalFonts();

        for (const font of array) {
          // blob() returns a Blob containing the bytes of the font.
          const bytes = await font.blob();
          console.log(`bytes.size = ${bytes.size}`);
          console.log(`bytes.type = ${bytes.type}`);
          // process font
        };
      } 
      catch (e) {
        console.warn(`Error: ${e.message}`);
      }
    };

</script>

</body>
</html>

Here I am getting local fonts and processing it. It works but I need to move font processing part to worker thread. I cant move everything because queryLocalFonts only works on main thread.

Here is my try:

<!DOCTYPE html>
<html>

<body>
  <button type="button" onclick='UseLocalFontsButton()'>Click Me!</button>

  <script>

    async function UseLocalFontsButton() {
      try {
        const array = await self.queryLocalFonts();

        let worker = new Worker('worker.js');
        worker.postMessage(JSON.stringify(array));
      } 
      catch (e) {
        console.warn(`Error: ${e.message}`);
      }
    };

</script>

</body>
</html>

And the worker:

(function () {
    onmessage = async function handleMessageFromMain(msg) 
    {
        var array = JSON.parse(msg.data);

        console.log('array = ', array);

        try {
            for (const font of array) {
                // blob() returns a Blob containing the bytes of the font.
                const bytes = await font.blob();
                console.log(`bytes.size = ${bytes.size}`);
                console.log(`bytes.type = ${bytes.type}`);
                // process font
            };
        } catch (e) {
            console.warn(`Error: ${e.message}`);
        }
    };
})();

I am getting error: Error: font.blob is not a function . Looks like font object is not properly copied to worker thread. Can you hint how that can be done?

You don't need to serialize your data to JSON when you post it to a Worker (or other MessagePort objects for that matter); the postMessage() method has its own cloning algorithm able to pass many different JS object types that JSON doesn't support.

And while FontData is not part of these many object types, Blob is. So what you need to do is to extract all the your FontData instances as Blob and send these Blob objects to your worker.

That would give:

// main script
async function UseLocalFontsButton() {
  try {
    const fonts = await self.queryLocalFonts();
    const toTransfer = [];
    for(const font of fonts) {
      toTransfer.push({
        // You're free to add whatever other info you need
        name: font.postscriptName,
        blob: await font.blob()
      });
    }
    const worker = new Worker("worker.js");
    worker.postMessage(toTransfer);
    worker.onmessage = ({data}) => {
      log(data);
    }
  } 
  catch (e) {
    log(`Error: ${e.message}`);
  }
};
// worker script
onmessage = async ({data}) => {
  postMessage(`Received ${data.length} Blobs`);
  for(const {blob, name} of data) {
    const buf = await blob..arrayBuffer();
    // Do your analysis on the font's data
  }
};

Live example as a Glitch project since StackSnippet's don't allow access to local fonts. ( editor ).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM