QJSEngine copy?
-
Is there a way how to copy one instance of QJSEngine to another including variables and functions?
QJSEngine engine1, engine2; engine1.evaluate("function sum(x, y){ return x + y;}"); engine1.globalObject().setProperty("a", 1); engine1.evaluate("var b = 2;"); //something like engine2 = engine1; qDebug() << engine2.evaluate("sum(a,b)").toString(); //3
-
Is there a way how to copy one instance of QJSEngine to another including variables and functions?
QJSEngine engine1, engine2; engine1.evaluate("function sum(x, y){ return x + y;}"); engine1.globalObject().setProperty("a", 1); engine1.evaluate("var b = 2;"); //something like engine2 = engine1; qDebug() << engine2.evaluate("sum(a,b)").toString(); //3
Hi, and welcome!
@Tarae said in QJSEngine copy?:
Is there a way how to copy one instance of QJSEngine to another
No.
QJSEngine
is aQObject
, and QObjects cannot be copied.However, you can copy the engine's Global Object (JavaScript object): https://doc.qt.io/qt-5/qjsengine.html#globalObject
-
Hi, and welcome!
@Tarae said in QJSEngine copy?:
Is there a way how to copy one instance of QJSEngine to another
No.
QJSEngine
is aQObject
, and QObjects cannot be copied.However, you can copy the engine's Global Object (JavaScript object): https://doc.qt.io/qt-5/qjsengine.html#globalObject
@JKSH Thank you.
But I can't see, how a copy of global object can solve my problem.
Is there a way how to create another engine with copy of global object?// I have engine1 with variables and functions. QJSEngine engine1; engine1.evaluate("function sum(x, y){ return x + y;}"); engine1.globalObject().setProperty("a", 1); engine1.evaluate("var b = 2;"); // I create copy of global object, how you suggest. QJSValue globalObject = engine1.globalObject(); QJSValue copyOfGlobalObject = deepCopy(globalObject); //BTW How to do deep copy of QJSValue if it is a object (isObject() returns true)? //And how to create new engine when I have copy of global object? // I would need something like this: QJSEngine engine2 = QJSEngine(copyOfGlobalObject); //creates instance of engine with global object // or this: QJSEngine engine2; engine2.globalObject() = copyOfGlobalObject; // sets global object of engine qDebug() << engine2.evaluate("sum(a,b)").toString(); //3
-
@JKSH Thank you.
But I can't see, how a copy of global object can solve my problem.
Is there a way how to create another engine with copy of global object?// I have engine1 with variables and functions. QJSEngine engine1; engine1.evaluate("function sum(x, y){ return x + y;}"); engine1.globalObject().setProperty("a", 1); engine1.evaluate("var b = 2;"); // I create copy of global object, how you suggest. QJSValue globalObject = engine1.globalObject(); QJSValue copyOfGlobalObject = deepCopy(globalObject); //BTW How to do deep copy of QJSValue if it is a object (isObject() returns true)? //And how to create new engine when I have copy of global object? // I would need something like this: QJSEngine engine2 = QJSEngine(copyOfGlobalObject); //creates instance of engine with global object // or this: QJSEngine engine2; engine2.globalObject() = copyOfGlobalObject; // sets global object of engine qDebug() << engine2.evaluate("sum(a,b)").toString(); //3
@Tarae The documentation says (https://doc.qt.io/qt-5.12/qjsvalue.html#details ):
Note that a QJSValue for which isObject() is true only carries a reference to an actual object; copying the QJSValue will only copy the object reference, not the object itself. If you want to clone an object (i.e. copy an object's properties to another object), you can do so with the help of a for-in statement in script code, or
QJSValueIterator
in C++.I believe you can use
QJSValueIterator
to iterate across every property in the 1st global object. Then, you can copy each property into the 2nd global object. -
@Tarae The documentation says (https://doc.qt.io/qt-5.12/qjsvalue.html#details ):
Note that a QJSValue for which isObject() is true only carries a reference to an actual object; copying the QJSValue will only copy the object reference, not the object itself. If you want to clone an object (i.e. copy an object's properties to another object), you can do so with the help of a for-in statement in script code, or
QJSValueIterator
in C++.I believe you can use
QJSValueIterator
to iterate across every property in the 1st global object. Then, you can copy each property into the 2nd global object.@JKSH OK, thank you for help, it looked great at first, but there is another problem: cannot set value created in a different engine
QJSEngine engine1, engine2; engine1.evaluate("function sum(x, y){ return x + y;}"); engine1.globalObject().setProperty("a", 1); engine1.evaluate("var b = 2;"); QJSValueIterator it(engine1.globalObject()); while (it.hasNext()) { it.next(); qDebug() << it.name() << ": " << it.value().toString(); engine2.globalObject().setProperty(it.name(), it.value()); } qDebug() << engine2.evaluate("sum(a,b)").toString(); //3
output looks like this:
... "sum" : "function sum() { [native code] }" QJSValue::setProperty(sum) failed: cannot set value created in a different engine "a" : "1" QJSValue::setProperty(a) failed: cannot set value created in a different engine "b" : "2" QJSValue::setProperty(b) failed: cannot set value created in a different engine "sum" : "function sum() { [native code] }" QJSValue::setProperty(sum) failed: cannot set value created in a different engine "a" : "1" QJSValue::setProperty(a) failed: cannot set value created in a different engine "b" : "2" QJSValue::setProperty(b) failed: cannot set value created in a different engine "ReferenceError: a is not defined"
Any idea how to solve this?
-
Hmm... That's unfortunate.
For things like numbers/strings you could bypass the restriction by calling
QJSValue::toNumber()
/QJSValue::toString()
first before callingsetProperty()
. I can't think of a way to copy functions though.Can you elaborate on why you want to copy the engine?
-
Hmm... That's unfortunate.
For things like numbers/strings you could bypass the restriction by calling
QJSValue::toNumber()
/QJSValue::toString()
first before callingsetProperty()
. I can't think of a way to copy functions though.Can you elaborate on why you want to copy the engine?
@JKSH What I want to accomplish is creating a lot of engines. All engines share some functions and variables. But not all of them, I can't use one engine for everything. I could define all functions and variables in each engine, but running
JSEngine::execute()
takes a lot of time. So I wanted to create one engine, define shared functions and variables in it and copy it to others engines.Code:
What I have:QString sharedScript = readFile("shared_script.js"); //large file QJSEngine engine1; engine1.evaluate(sharedScript); //takes long QString engine1script = readFile("script1.js"); engine1.evaluate(engine1script); //... QJSEngine engine1000; engine1000.evaluate(sharedScript); //takes long QString engine1000script = readFile("script1000.js"); engine1000.evaluate(engine1000script);
What I want:
QString sharedScript = readFile("shared_script.js"); //long file QJSEngine sharedEngine; sharedEngine.evaluate(sharedScript); //takes long QJSEngine engine1 = copyOf(sharedEngine); //fast QString engine1script = readFile("script1.js"); engine1.evaluate(engine1script); //... QJSEngine engine1000 = copyOf(sharedEngine); //fast QString engine1000script = readFile("script1000.js"); engine1000.evaluate(engine1script);
-
@JKSH What I want to accomplish is creating a lot of engines. All engines share some functions and variables. But not all of them, I can't use one engine for everything. I could define all functions and variables in each engine, but running
JSEngine::execute()
takes a lot of time. So I wanted to create one engine, define shared functions and variables in it and copy it to others engines.Code:
What I have:QString sharedScript = readFile("shared_script.js"); //large file QJSEngine engine1; engine1.evaluate(sharedScript); //takes long QString engine1script = readFile("script1.js"); engine1.evaluate(engine1script); //... QJSEngine engine1000; engine1000.evaluate(sharedScript); //takes long QString engine1000script = readFile("script1000.js"); engine1000.evaluate(engine1000script);
What I want:
QString sharedScript = readFile("shared_script.js"); //long file QJSEngine sharedEngine; sharedEngine.evaluate(sharedScript); //takes long QJSEngine engine1 = copyOf(sharedEngine); //fast QString engine1script = readFile("script1.js"); engine1.evaluate(engine1script); //... QJSEngine engine1000 = copyOf(sharedEngine); //fast QString engine1000script = readFile("script1000.js"); engine1000.evaluate(engine1script);
@Tarae As a workaround, try splitting shared_script.js into 2 parts:
(i) A part that contains just the function definitions
(ii) A part that contains function calls.My hypothesis is that
evaluate()
-ing (i) should be faster than (ii).So, you could try:
- Run (i) and (ii) in engine1
- Run only (i) in engine2
- Use
QJSValueIterator
to copy non-function properties to engine2, usingQJSValue::toNumber()
/QJSValue::toString()
/QJSValue::toVariant()
first
Another thing you could try is putting different engines in different threads (although you must be careful with thread programming)