Обещание JavaScript застревает при разрешении

У меня есть асинхронная функция, которую я выполняю несколько раз (2), но по какой-то причине обещание зависает при разрешении. Он выполняет resolve(), но ничего не делает.

Вот функция (в основном создает большой двоичный объект из 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;
});
}

А вот и карта задач:

            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');
            });

Он застревает при первом разрешении(). Это вывод консоли:

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...

person Fabis    schedule 15.04.2014    source источник


Ответы (3)


У вас есть переменная g, которую вы сравниваете с 0, но вы нигде не определили g.

Причина, по которой вы этого не видели, заключается в том, что собственные промисы (или jQuery) автоматически не отслеживают возможные необработанные отклонения.

Вы можете проверить наличие ошибок, добавив .catch в конец цепочки, и посмотреть, не пошло ли что-то не так.

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

Который показал бы вам проблему.

В качестве альтернативы используйте более мощную библиотеку, такую ​​как Bluebird, которая будет предупреждать вас в случае необработанных отклонений.

person Benjamin Gruenbaum    schedule 15.04.2014
comment
.catch(), я этого не знал. Где-то реф?! Разве вы не имеете в виду .fail() вместо этого? - person A. Wolff; 15.04.2014
comment
@A.Wolff уверен, что github.com/domenic/ это EcmaScript 6 обещает спецификацию. Он также существует в большинстве реализаций ($q, Q, rsvp, vow, bluebird, when и большинстве других). - person Benjamin Gruenbaum; 15.04.2014
comment
Выглядит отлично! Спасибо за обмен! - person A. Wolff; 15.04.2014
comment
comment
@dusky Спасибо за ссылку! - person A. Wolff; 29.10.2014

Дерп, похоже переменная g появилась из ниоткуда. Когда я изменил его на i, он начал работать. Почему я не получил ошибку в консоли? Обещания каким-то образом подавляют ошибки?

person Fabis    schedule 15.04.2014
comment
Вау, я догадался, что мой ответ был неправильным, но, видимо, он был точным, я восстановил его. - person Benjamin Gruenbaum; 15.04.2014
comment
@Fabis, если вы используете then или catch, см. promise.then проглатывание ошибок (используйте курсоры для перемещения) - person Mariusz Nowak; 15.04.2014

Вы столкнулись с проблемой проглоченного исключения.

Предлагаемый catch в принятом ответе на самом деле такой же, как и then(null, fn), это также функция преобразования, которая будет проглатывать возможные исключения (поэтому это не настоящее решение вашей проблемы).

Если вы просто хотите обработать значение, самый чистый способ - через done (без подразумеваемого проглатывания ошибок)

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

Однако имейте в виду, что нативные промисы не предоставляют done, и, поскольку не предлагается решения для проглатывания ошибок, лучше не использовать нативные промисы (пока это не будет решено) и вместо этого использовать одну из популярных библиотек JS (большинство из них предоставляют done).

Смотрите также:

person Mariusz Nowak    schedule 15.04.2014