Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

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" 1551450598462

    When 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 1551450570363

    The 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


Log in to reply