Catching error thrown in C++ code in Js.
-
Hello !
I'm running JS code with QJSEngine. This code calls C++ method, in which errors may occur. I'm looking for a way to get these errors back as a JS exception. Is this possible without having my Q_INVOKABLE methods return error objects and wrapping them in JS functions ?
class X : public QObject { Q_OBJECT public: X(QObject *parent=0); Q_INVOKABLE void foo(int arg) { if (arg == 0) { // Do something here that causes an exception in the js environment throw "InvalidArgException"; } } }; int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); QJSEngine eng(&app); X x(&app); eng.globalObject().setProperty("x", eng.newQObject(&x)); eng.evaluate("try { x.foo(0); } catch(e) { console.log(e); }"); }
Throwing an exception doesn't work at all, the application is terminated directly without returning to the calling Js environment.
-
A quick test reveals that it's not possible to use a js proxy to throw the exception.
If we replace the X::foo() method from my previous post with the following one:
Q_INVOKABLE void foo(int arg) { engine.evaluate("Raiser.raise('foo error')"); }
And call the following JS code with QJSEngine.evaluate(...):
var Raiser = { raise: function(err) { throw err; } }; try { x.foo(); console.log("after foo"); } catch (err) { console.log("Caught: " + err); }
We get "after foo", not "Caught: foo error". The exception raised in Raiser::raise is cleared before foo() returns.
The following code found in tests/auto/qml/qqmlecmascript/testtypes.cpp would do the trick, unfortunately, this requires the use of internals. Maybe a method could be added to the QJSEngine public API to wrap engine()->currentContext()->throwError() ?
void MyQmlObject::v8function(QQmlV4Function *function) { V8Engine::getV4(function->engine())->currentContext()->throwError(QStringLiteral("Exception thrown from within QObject slot")); }
-
Hi and welcome to devnet,
To discuss this suggestion, I'd recommend writing to the interest mailing list You'll find there Qt's developers/maintainers (this forum is more user oriented)
-
I've read that returning an Error object is the way to go, but I've not tried myself. To create one you would have either create one with in Javascript or probably it would do to return one from an failed call of
JSEngine::evaluate
The sole problem is your function would have to return aQJSValue
.you could try:
Q_INVOKABLE QJSValue foo(int arg) { return engine.evaluate("throw 'foo error'"); }
or
Q_INVOKABLE QJSValue foo(int arg) { return engine.evaluate("throw new Error('foo error')"); }
or
Q_INVOKABLE QJSValue foo(int arg) { return engine.globalObject().property("Error").callAsConstructor("foo error"); }
Let me know if eithere of those worked