Использование jQuery с массивом обещаний

Я пытаюсь загрузить серию шаблонов в массив, и у меня возникли проблемы с методом jQuery when (на основе этого ответа )

var files = [/*array of file names*/];
var templates = [];
files.forEach(function(file){
    templates.push(
        $.get('/temps/' + file + '.hbs').then(function(temp) {
            console.log('done loading', temp);
        })
    )
});
$.when.apply($, templates).then(function() {
    console.log(arguments); //"undefined"x10
});

Почему массив обещаний для when не создает массив из десяти моих шаблонов? Что здесь пошло не так?

Редактировать: очевидно, что отказ от метода then в каждом get немного приблизил меня:

templates.push($.get('/temps/' + file + '.hbs'));

Однако мне любопытно, когда я не могу использовать then здесь, а также когда

templates.push($.get('/temps/' + file + '.hbs')[0]) 

все еще дает мне массив undefineds. Первый элемент возвращаемого массива — это возвращаемые данные. Почему не работает нажатие этого первого элемента?


person 1252748    schedule 04.04.2016    source источник


Ответы (2)


Потому что промисы в массиве — это промисы для undefined, а не промисы для ваших шаблонов. Вам нужно будет использовать

$.get('/temps/' + file + '.hbs').then(function(temp) {
    console.log('done loading', temp);
    return temp;
//  ^^^^^^
})

чтобы получить обещание для шаблона, в противном случае он разрешается с неявным возвращаемым значением undefined. Помните, что then возвращает новое обещание для результата обратного вызова, а не исходное обещание.

person Bergi    schedule 04.04.2016
comment
Спасибо. Ты видишь мою правку? Это правильнее? - person 1252748; 04.04.2016
comment
Это работает довольно хорошо. Однако я пытаюсь вернуть эти данные другой функции. $.when.apply($, templates).then(function() { return arguments }); и сохраните данные в другой переменной. Так, например, весь ajax будет в функции doAjax(), и я пытаюсь сделать var templatesFromAjax = doAjax(), но получаю неопределенность, когда в следующей строке делаю `console.log(templatesFromAjax); - person 1252748; 04.04.2016
comment
Да, вообще не использовать then тоже правильно. Использование [0] не имеет смысла, так как промисы не имеют такого свойства. - person Bergi; 04.04.2016
comment
Вы можете использовать .then(function(){ return $.map(arguments, function(args) { return args[0]; }); }) для получения массива результатов ajax. jQuery.when — ужас по сравнению с промисами с несколькими возвращаемыми значениями. - person Bergi; 04.04.2016
comment
ужастик? Вы рекомендуете что-то еще? - person 1252748; 04.04.2016
comment
Вы также можете использовать стандартную функцию для реальных обещаний и полностью уклоняться от jQuery deferreds :-) - person Bergi; 04.04.2016
comment
К сожалению, браузеры, которые мне нужно поддерживать, исключают использование нативных промисов. Хотя all было бы прекрасно. Честно говоря, я нахожу методы промисов jQuery немного запутанными. У вас есть время, чтобы быстро поболтать, чтобы я мог немного показать вам, что я пытаюсь сделать? - person 1252748; 04.04.2016
comment
Вы также можете использовать любую из этих библиотек в качестве полифилла :-) - person Bergi; 04.04.2016
comment
Хе-хе, я думаю, что встретил бы некоторое сопротивление при импорте библиотеки промисов, просто загрузите несколько шаблонов. Но опять же, это, вероятно, сэкономило бы мне много времени этим утром! :) - person 1252748; 04.04.2016
comment
Сейчас я нахожусь в том, что я помещаю все gets в массив, а затем возвращаю массив. Затем в вызывающей его функции у меня есть forEach. Я хотел бы сделать что-то вроде getTemplates().then(function(temps){/*buildPage or something*/});, но получаю getTemplates.then is not a function. однако getTemplates.forEach выводит весь объект обещания, и я могу получить доступ к responseText, который содержит мое значение. Но вставить это в другой массив кажется слишком сложным. - person 1252748; 04.04.2016
comment
Давайте продолжим обсуждение в чате. - person 1252748; 04.04.2016
comment
Спасибо за вашу помощь этим утром. Одна вещь, которую я не понял о последней функции .then(function() { return $.map(arguments, function(args) { return args[0]; }); });, это то, как работает $.map. Я бы подумал, что arguments будет начальным массивоподобным объектом, по которому он повторяется. Однако, когда я ставлю точку останова в консоли на его операторы return, я вижу, что arguments каждый раз меняется. Что там происходит? - person 1252748; 05.04.2016
comment
@thomas: Вероятно, у вас есть arguments обратного вызова map в представлении области, а не arguments обратного вызова then. - person Bergi; 05.04.2016
comment
Держу пари, что это точно. Ваше здоровье. - person 1252748; 05.04.2016

Вы вызываете then, который возвращает другое обещание. Если вам просто нужен «побочный эффект», используйте вместо этого done.

person blockhead    schedule 04.04.2016