Remirror
Remirror

Reputation: 754

How to merge 2 serializable functions into 1 serializable function in JS?

As you know, there are certain cases (e.g., use in workers) when functions need to be serializable (and, at the other side, deserializable of course). I have such a case; a library function (i.e. I cannot change it) doSomething(serializableFunction) expects such a function from me. Also it expects that serializableFunction accepts 1 parameter x and gives x to it.

So far, this was not a problem for me; I had one function f(x) from another library that fulfilled my purposes (so I just called doSomething(f) so far). But now, I have a second serializable function g(x), also from a library, and I want the function I give to doSomething to execute either f or g, dependent on x. So I tried:

doSomething(function h(x) {
  if (x < 5) return f(x);
  else return g(x);
});

This would work well without serialization, but with it, an error is thrown of course because h is not serializable anymore: It calls f and g, which are no longer known at deserialization time!

So currently I'm doing:

doSomething(eval(`function h(x) {
  const f = ${f.toString()};
  const g = ${g.toString()};
  if (x < 5) return f(x);
  else return g(x);
}`));

This works, but it's a nightmare! So my question is: Is there any better approach to merge 2 serializable functions (like fand g) into 1 function that is also serializable? Note that I cannot change any of f, g, or doSomething, just h!

Upvotes: 0

Views: 64

Answers (1)

ikhvjs
ikhvjs

Reputation: 5927

I think of a solution replacing eval with new Funciton. Not the best, but a bit better.

Example below:

function f(a) {
    console.log("f", a);
}

function g(b) {
    console.log("f", b);
}

function doSomething(func) {
    const y = 1;
    func(y);
}

const funcBody = `return function () {
    const f = ${f.toString()};
    const g = ${g.toString()};
    if (x < 5) return f(x);
    else return g(x);
  }()`;

const func = new Function("x", funcBody);

doSomething(func);

Or you can add some abstraction like below:

function f(a) {
    console.log("f", a);
}

function g(b) {
    console.log("f", b);
}

function doSomething(func) {
    const y = 1;
    func(y);
}

const getFuncArray = (name = "x") => [
    name,
    `return function () {
        const f = ${f.toString()};
        const g = ${g.toString()};
        if (${name} < 5) return f(${name});
        else return g(${name});
    }()`,
];

const res = new Function(...getFuncArray());

doSomething(res);

Upvotes: 0

Related Questions