Question

I have an async function that I do multiple times (2), but for some reason the promise get stuck at resolve. It executes resolve(), but doesn't do anything.

Here's the function (basically creates a blob from an URL):

function getBlobAt(url, callback) {
console.log("New getBlobAt Call");
return new Promise(function(resolve) {
    console.log("getBlobAt Promise Created");
    window.URL = window.URL || window.webkitURL;
    var xhr = new XMLHttpRequest();
    xhr.open('GET', url, true);
    xhr.responseType = 'blob';
    xhr.onload = function () {
        console.log("getBlobAt promise completed, resolving...");
        var burl = window.URL.createObjectURL(this.response);
        console.log("getBlobAt promise completed, resolving2...");
        resolve(burl);
        console.log("getBlobAt promise completed, resolving3...");
        //window.URL.revokeObjectURL(burl); //DO THIS WHEN LOADING NEW SONG
    };
    console.log("getBlobAt xhr.send() and callback");
    xhr.send();
    callback(xhr);
    //return xhr;
});
}

And here's the task map:

            var taskstrings = [endmp3, albumart];
            var getBlobTasks = taskstrings.map(function (xurl, i) {
                return function () {
                    console.log("Running a getBlobTask");
                    return getBlobAt(xurl, function (xhr) {
                        console.log("getBlobTask callback");
                        if (g == 0) { //First one is always the mp3 link
                            current_xhr = xhr;
                        } else {
                            current_xhr_album = xhr;
                        }
                    }).then(function (res) {
                        console.log("getBlobTask complete - returning!");
                        if (g == 0) { //First one is always the mp3 link
                            current_blob = res;
                        } else {
                            current_blob_album = res;
                        }
                        return res;
                    });
                };
            });

            var q = getBlobTasks[0](); // start the first one
            for (var i = 1; i < getBlobTasks.length; i++) q = q.then(getBlobTasks[i]);
            q.then(function (result) {
                //Both globs have been returned
                console.log("All getBlobTasks completed!");
                setPlayer(current_blob, current_blob_album);
                target.attr('class', 'glyphicon glyphicon-pause');
            });

It gets stuck at the first resolve(). This is the console output:

Running a getBlobTask
New getBlobAt Call
getBlobAt Promise Created
getBlobAt xhr.send() and callback
getBlobTask callback
getBlobAt promise completed, resolving... 
getBlobAt promise completed, resolving2...
getBlobAt promise completed, resolving3...
Was it helpful?

Solution

You have a g variable you check against 0 but you did not define g anywhere.

The reason you did not see this is that native (or jQuery) promises do not automatically track possibly unhandled rejections.

You can check for errors by appending a .catch to the end of the chain and see if anything went wrong.

q.then(function (result) {
    ...
}).catch(function(e){
     console.log(e.message);
     console.log(e.stack);
});

Which would have shown you the issue.

Alternatively, use a stronger library like Bluebird that will alert you in the case of unhandled rejections.

OTHER TIPS

Derp, looks like the variable g appeared out of nowhere. When I changed it to i, it started working. Why didn't I get an error in the console, though? Do promises suppress errors in some way?

You've run into swallowed exception issue.

Proposed catch in accepted answer is actually same as doing then(null, fn), it's also transformation function that will swallow eventual exceptions (so not real solution for your problem).

If you just want to process the value, cleanest way is via done (with no error swallowing implied)

q.done(function (result) {
    // Process the result
});

However mind that native promises do not provide done, and as there's no solution for error swallowing proposed, it's best to not use native promises (until that's solved) and use one of the popular JS libraries instead (most of them provide done).

See also:

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top