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

Angular 6 Failed to execute 'postMessage' on 'Worker' #249

Closed
kzmv opened this issue Mar 15, 2019 · 10 comments
Closed

Angular 6 Failed to execute 'postMessage' on 'Worker' #249

kzmv opened this issue Mar 15, 2019 · 10 comments

Comments

@kzmv
Copy link

kzmv commented Mar 15, 2019

Hello, I've been trying to use this example to make comlinkjs work in Angular: https://medium.com/lacolaco-blog/enjoyable-webworkers-in-angular-41cfeb0e6519
(example is working when checked out: example

However I can't seem to replicate the example and I always get this error in my project

ERROR Error: Uncaught (in promise): DataCloneError: Failed to execute 'postMessage' on 'Worker': Symbol(Symbol.toPrimitive) could not be cloned.
Error: Failed to execute 'postMessage' on 'Worker': Symbol(Symbol.toPrimitive) could not be cloned.

Here is my setup

//generate-data-worker.ts

import { expose } from 'comlinkjs';

export class GenerateData {
  generateData(source: string) {
    return new Promise((resolve, reject) => {
      resolve( "TEST" );
    });
  }
}

expose({GenerateData}, self);
//generate-data.service.ts
import {Injectable} from '@angular/core';
import {proxy} from 'comlinkjs';


const GenerateDataWokrer = proxy<
  typeof import('../worker/generate-data').GenerateData
  >(
  new (Worker as any)('../worker/generate-data', { type: 'module' })
);

@Injectable({
  providedIn: 'root'
})
export class GenerateDataService {
  async generateData(source: string): Promise<any> {
    const worker = await new GenerateDataWokrer();
    return await worker.generateData(source);
  }
}

calling it as:

this.genDataService.generateData(``).then((value) => {
      console.log(value)
    });

Can you help me understand from where is the error coming from?

@surma
Copy link
Collaborator

surma commented Mar 18, 2019

I’m not sure why the error is looking like that for you. When I run your code (without the Angular bits), I get an error that what I am calling with new is not a constructor, which is correct! You are exposing an object from the worker, that contains the class. So you need to access that constructor when calling new:

-  const worker = await new GenerateDataWokrer();
+  const worker = await new GenerateDataWokrer.GenerateData();

@surma surma closed this as completed Mar 18, 2019
@kzmv
Copy link
Author

kzmv commented Mar 19, 2019

Hey I continue getting

Uncaught (in promise) DOMException: Failed to execute 'postMessage' on 'Worker': Symbol(Symbol.toPrimitive) could not be cloned.

Do you happen to have a working angular example with comlink? I have found only the one I've mentioned earlier.

@surma
Copy link
Collaborator

surma commented Mar 19, 2019

Can you host your code on a Glitch? This seems to be Angular-specific.

@surma surma reopened this Mar 19, 2019
@kzmv
Copy link
Author

kzmv commented Mar 19, 2019

I can't share my current project sadly. I will show the other project ( which will most probably work) in Glitch soon.

I kind of wanted to understand what does the error mean so I know what I'm looking for as I debug.

@surma
Copy link
Collaborator

surma commented Mar 20, 2019

The error implies that the message payload contains an object with Symbol.toPrimitive in it. Symbols are not structured cloneable, so sending the message to the worker fails.

Function parameters and return values are part of the message, so that’s usually where the cause lies. From your example, you are only sending strings, so those should be fine. My guess is that Angular is injecting the symbol somewhere for some reason. But I am out of my depth there.

@kzmv
Copy link
Author

kzmv commented Mar 20, 2019

Thank you for clarifying. I'm unable to reproduce the problem in a standalone project (it works there).

I believe this is some underlying angular configuration on my side. Let's close the issue and I will respond when I find a solution.

@kzmv kzmv closed this as completed Mar 20, 2019
@sansato
Copy link

sansato commented May 1, 2019

I encountered this same message (Symbol(Symbol.toPrimitive) could not be cloned) while using comlink, with the interesting finding that it seems to be triggered by placing a 'debugger' statement soon before the postMessage. Aggravating. 😀

Removing the debugger statement removes the symptom (it's sometimes replaced by a different error [with its own separable cause] that can make troubleshooting confusing).

Searching the interwebs for that message leads to a Googlewhack on this ticket.

Lacking any further evidence, I'm thinking Chrome devtools might be adding this symbol as an implicit flag, maybe as part of its "Scope" panel? Maybe this can help with reproduction.

... and now I got further evidence.

In the case I have in hand right now:

[service worker]
comlink.expose(new SomeThing());

[DOM thread]
const proxy = comlink.proxy(pipe1)
proxy.someMethod(someValue)

the someMethod() being called was returning this (the expose()'d object, an instance of an ES6 class, transpiled with Babel 7.1). I think that's generally matching descriptions above.

In the DOM thread, here's a stack trace goes with the error message.

comlink.js:250 Uncaught (in promise) DOMException: Failed to execute 'postMessage' on 'MessagePort': Symbol(Symbol.toPrimitive) could not be cloned.
    at eval (webpack:///./node_modules/comlink/comlink.js?:250:18)
    at new Promise (<anonymous>)
    at pingPongMessage (webpack:///./node_modules/comlink/comlink.js?:241:12)
    at eval (webpack:///./node_modules/comlink/comlink.js?:69:32)
    at Object.apply (webpack:///./node_modules/comlink/comlink.js?:267:20)
    at eval (webpack:///./src/helpers/MyStuff.js?:45:9)

^^^ ONLY when debugger is used right before the call to proxy.doSomething(someArg).

In the service worker, this error is thrown (either with or without debugger) - simply a result of trying to return this.

comlink.js:124 Uncaught (in promise) DOMException: Failed to execute 'postMessage' on 'MessagePort': function () { [native code] } could not be cloned.
    at MessagePort.eval (webpack:///./node_modules/comlink/comlink.js?:124:25)

I checked to see whether the error at 250 was possibly being thrown from the worker, by adding logging in 2 catch() handlers in comlink.js. Nope.

That leads me back to the devtools theory. I traded out someArg for {}, a new object that devtools shouldn't be able to see. Same results. I looked at the proxy for someMethod, didn't locate any toPrimitive in it. Now I'm stumped for sure.

Of course, removing return this is fixing my current problem.

@sansato
Copy link

sansato commented May 1, 2019

Note: after fixing my real problem, the debugger statement continues to cause the error to be thrown, yet the service worker does certainly receive the message...

@kzmv
Copy link
Author

kzmv commented May 8, 2019

are you using Angular 6? for me it worked after migrating to 7.

@sansato
Copy link

sansato commented May 8, 2019

No, it's a React app, plain javascript through comlink for some share with >1 browser tabs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants