Promise chaining in QML (Qt 5.12)
-
I was excited to update to Qt 5.12 and replace the Promise library I was using (https://github.com/benlau/quickpromise) with native Promises. However, reality of it has not been kind to me. I have a situation where I am chaining several Promises but they are not resolving in the correct order. Here a simplified version of my code that reproduces my issue:
var p1 = new Promise(function(resolve, reject) { var xhr = new XMLHttpRequest(); xhr.open("GET", "https://httpbin.org/json", true); xhr.onreadystatechange = function() { if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) { console.log("p1 resolved", new Date().getTime()); resolve(JSON.parse(xhr.response)); } }; xhr.send(); }); p1.then(function(data) { return new Promise(function(resolve, reject) { var xhr = new XMLHttpRequest(); xhr.open("GET", "https://httpbin.org/", true); //append data to url xhr.onreadystatechange = function() { if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) { console.log("p2 resolved", new Date().getTime()); resolve(); } }; xhr.send(); }); }).then(function() { console.log("both promises complete", new Date().getTime()); });
When I run this code in a browser (https://codepen.io/sirhcybe/pen/OqyKom), I get the following console output:
"p1 resolved" 1551450598423
"p2 resolved" 1551450598461
"both promises complete" 1551450598462When I run the code from QML in a Qt application I get the following console output:
qml: p1 resolved 1551450570323
qml: both promises complete 1551450570326
qml: p2 resolved 1551450570363The promise chaining seems to work if I create both promises at the same time and chain them like this:
var p1 = new Promise(...); var p2 = new Promise(...); p1.then(function(data) { return p2; }).then(function() { console.log('done') });
However, I can't use this because I need the results from p1 to make the call to p2. Does anyone know how to fix this so that I can use the results from my first promise in my second promise?
-
I realized what's going on. It looks like returning a new Promise makes the promise the result of the first promise instead of doing the normal thing of merging/flattening the promises. So this code prints 'done' after both promises are complete:
var p1 = new Promise(...); p1.then(function(data) { return new Promise(...); }) .then(function(p2) { p2.then(function() { console.log('done') }; });
I still have a problem because these promises are executed in a function of a service class and I want the function to return a single Promise that just resolves with the data I need. I don't want the functions calling the functions in the service class to have to know that this method makes 3 XHR requests so you have to have 3 layers of thens to get your data. This is unreadable and brittle. I'm still looking for a better solution.
-
Turns out this is a known bug: https://bugreports.qt.io/browse/QTBUG-71329