2015-09-16 3 views
2

Сегодня утром я работал над приложением и нашел что-то интересное ... интересно, может ли кто-нибудь объяснить поведение, которое я вижу.разница в том, как вернуть обещание?

Я создаю набор отчетов, который требует загрузки некоторых предварительных условий до того, как отчеты будут запущены. Мне нужны мои данные из Firebase, и мне также нужно динамически загружать некоторые шаблоны Handlebars для отображения этих данных. Поскольку есть несколько страниц отчета, я сделал загрузку данных и шаблонов, используя отложенные объекты. Так что в моем reports.js файл, у меня есть что-то вроде этого:

var report = {}; 

(function($) { 

    report = { 
     prefetchData : function() { 
      return $.Deferred(function(d) { 
       // get data 
       d.resolve(); 
      }).promise(); 
     }, 

     prefetchTemplates : function() { 
      return $.Deferred(function(d) { 
       var templates = $.map($("[data-template]"), function(o) { 
         return $(o).data('template'); 
        }), 
        getTemplate = function(name) { 
         $.get(name, function(data) { 
          report.templates[name] = data; 
         }); 
        }, 
        toDownload = []; 

       for (var i = 0; i < templates.lenght; i++) { 
        toDownload.push(getTemplate(templates[i])); 
       } 

       $.when.apply($, toDownload).done(function() { 
        d.resolve(); 
       }).fail(function() { 
        d.reject(); 
       }); 
      }).promise(); 
     } 
    }; 

})(jQuery); 

Моя страница отчета сценарий выглядит следующим образом:

var report = report || {}; 

(function($) { 

    $.when(
     report.prefetchData(), 
     report.prefetchTemplates() 
    ).done(function() { 
     // load the charts, etc. 
    }); 

})(jQuery); 

То, что я обнаружил, что карты начнут оказывать до шаблона был скачан, особенно если я запускал страницы в более медленной среде. Поэтому я изменил prefetchTemplates функцию следующим образом:

prefetchTemplates : function() { 
    var d = $.Deferred(), 
     templates = $.map($("[data-template]"), function(o) { 
      return $(o).data('template'); 
     }), 
     getTemplate = function(name) { 
      $.get(name, function(data) { 
       report.templates[name] = data; 
      }); 
     }, 
     toDownload = []; 

    for (var i = 0; i < templates.lenght; i++) { 
     toDownload.push(getTemplate(templates[i])); 
    } 

    $.when.apply($, toDownload).done(function() { 
     d.resolve(); 
    }).fail(function() { 
     d.reject(); 
    }); 

    return d.promise(); 
} 

Теперь, даже в самой медленной среде, мои шаблоны всегда загружена до того, графики начинают оказывать, что поведение я хочу. Поэтому мой вопрос: в чем разница между return $.Deferred(function(d) {...}).promise(); и var d = $.Deferred(); ... return d.promise();? Иными словами, если основной метод .done() не будет срабатывать до тех пор, пока все возвращенные обещания не будут решены, почему это имеет значение, если моя функция завершена в отложенном обратном вызове и выполняется «нормально»? Является ли это просто вопросом времени, или отложенный объект работает по-разному в зависимости от того, как он создан?

+2

Я думаю, что вы забыли вернуть обещание от 'getTemplate', возможно, это ошибка копирования-вставки, потому что это сделало бы решение $ .when мгновенно, а не когда оно будет иметь данные. –

+0

Но функция 'getTemplate' не предназначена для решения обещания; он просто предназначен для заполнения объекта report.templates. Разрешение должно выполняться в функции '$ .when()' после того, как все шаблоны будут сохранены. Разве я совершенно не понимаю, что вы говорите? – mounty

+1

Если вы не вернетесь с getTemplate, то $ .when бесполезно, потому что, если ему не дают обещания подключиться, он просто разрешит мгновенно. Ваш текущий код в основном разрешает 'd' почти сразу. –

ответ

1

Ваше «рабочее» решение просто случайно работает, а не фактически делает то, что вы думаете, что оно делает.

Когда вы перебираете свои данные и заполняете массив toDownload, вы заполняете его значением undefined, потому что ваша функция getTemplate ничего не возвращает. Вы должны вернуть ему обещание.

getTemplate = function(name) { 
    return $.get(name, function(data) { 
     report.templates[name] = data; 
    }); 
}, 

Насколько

return $.Deferred(function(d) {...}).promise(); 

против

var d = $.Deferred(); ... return d.promise(); 

Они точно так же и не должны выполняться по-другому. Я бы назвал совпадение или удобное время.