How to cope with the asynchronous-ness of Qt.import() ?
-
Hi.
I want a QML component to call a js domain/business-specific library, itself calling a generic library. Exactly the use case depicted by the Including a JavaScript Resource from Another JavaScript Resource documentation entry:
ui.qml
→script.js
→factorial.js
.In the example,
script.js
callsQt.include("factorial.js")
, then immediately calls thefactorial(value)
method included fromfactorial.js
.But trying exactly this in my project, instead of working as expected, I end up with error
script.js:6: ReferenceError: factorial is not defined
:-/ . Why? BecauseQt.include()
is asynchronous! As mentioned by Qt.include()'s documentation,"
Qt.include()
returns an object that describes the status of the operation [...]. The status property will be updated as the operation progresses. If provided,callback
is invoked when the operation completes. The callback is passed the same object as is returned from theQt.include()
call."And indeed, true to the method documentation, if trying a synchronous approach, the
Qt.include()
call yields the following object:{ "OK":0, "LOADING":1, "NETWORK_ERROR":2, "EXCEPTION":3, "status":1 }
status
equalsLOADING
, our child method hasn't been copied to caller scope yet. Okay. So instead of going synchronous, let's play ball and make the example async:// script.js function showCalculations(value) { console.log("Just a top-level scope stub, to be replaced on import of factorial.js"); } Qt.include("factorial.js", function(includeStatus) { console.log(includeStatus); // logs 0 now, great showCalculations = function(value) { console.log( "Call factorial() from script.js:", factorial(value)); } });
The good news here is that the
includeStatus.status
being logged is now0
, the callback did fire on successful import as promised.But the bad news is of course that, because the
include
is asynchronous and non-blocking, it will not not be resolved at the time QML needs it, and QML will use the shim, loggingJust a top-level scope stub...
. Of course, not including a stub will result in worse: the function not being found.→ Am I missing anything / is the documentation effectively incorrect? What could differ in my case? My qml and scripts are part of a
qrc
, could it be interfering?EDIT: posted too on the qt-development mailing list.
EDIT2: created QTBUG-49373 - [QtQuick] Is Qt.include() really async? If yes, documentation needs fixing.
-
Hi,
If I understand correctly what you want to achieve you can do it in two different ways:-
function showCalculations(value) { Qt.include("factorial.js", function(includeStatus) { console.log(includeStatus); // logs 0 now, great console.log("Call factorial() from script.js: "+factorial(value)); } } // call from QML: showCalculations(someValue);
-
function showCalculations(value, callback) { Qt.include("factorial.js", function(includeStatus) { console.log(includeStatus); // logs 0 now, great callback(factorial(value)); } } // call from QML showCalculations(value, function(result){ // do something useful with result });
Best regards.
-
-
@unai_i sure, thanks for bringing this. But compared to a regular
import
statement,- It adds callback nested-ness and noise...
- ... and it does so in each function requiring a
Qt.include
d symbol, bringing even more noise and repetition :-/ (and maybe slowing things down?), contrarily to basically all language'simport
statement, which makes foreign symbols available in the whole current file.
I'm mourning a simple synchronous CommonJS-style
var mylib = require('mylib')
. Thanks for confirming the documentation lies. -
Good news! My use case is actually well covered by simply using a regular
.import "thing.js" as Thing
. I don't need the specific namespace-less behavior ofQt.include
; I just happened to miss.import
when reading the doc, thus failing to understand thatQt.include
is only a second import mechanism to be used instead of.import
under very specific (documented) circumstances.→ Doc might still deserve clarification of the async behavior, but my initial problem is gone with using
.import
. I updated the QTBUG