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

64 views Asked by At

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!

1

There are 1 answers

7
ikhvjs On

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);