【问题标题】:Wait for all .then() to be executed before firing a single function [duplicate]在触发单个函数之前等待所有 .then() 执行[重复]
【发布时间】:2015-10-08 10:27:00
【问题描述】:

我正在尝试在加载所有模板时触发一个函数。这是通过每个模板的 loadTemplate 函数完成的。

我的问题是如何监听所有 .then() 完成,然后才触发我的 foo() 函数。

我尝试过使用 when() 和 promise,但是我没有成功地将它们绑定到外部,而我已经设法将它绑定到 loadTemplate(这不是我想要的为)。

我总是可以将每个 loadTemplate 绑定到一个计数器,并在每次迭代时检查计数器是否已达到每个模板的数量,但我确信有一种更优雅的方法可以做到这一点。

这是循环代码:

    $.each(templates.hbs, function(idx, template) {
        loadTemplate(template.name)
          .then(function(templateStr){
            var compiledTemplate = Handlebars.compile(templateStr);
            if(template.isPartial){
              Handlebars.registerPartial(template.key, compiledTemplate);
            }
            templates[template.key] = compiledTemplate;
          });
      });

以及触发后的函数:

    function templateDone(){
      console.log("done!");
    }

感谢您的帮助!

编辑:也包括 loadTemplate 代码:

    function loadTemplate (template) {
      return new Promise(function (resolve, reject) {
        $.ajax({
          url: config.wwwroot + '/folder/' + template + '.hbs',
          async: false,
          success: function (result) {
            resolve(result);
          },
          error: reject
        });
      });
    }

【问题讨论】:

  • 但我确信有更优雅的方法可以做到这一点我不太确定。

标签: javascript jquery ajax


【解决方案1】:

当您的 loadTemplate 函数返回一个承诺时,您可以使用 .when()。请参阅 documentation 示例,了解等待解决多个 Promise 的情况。

你可以这样做:

var promises = [];

$.each(templates.hbs, function (idx, template) {
    promises.push(loadTemplate(template.name));
});

$.when.apply($, promises).then(templateDone);

至于您的 loadTemplate 函数,您不需要创建自己的 Promise。 $.ajax 默认返回一个承诺。

function loadTemplate(template) {
    return $.ajax({
        /* ... */
    });
}

看看这有什么不同吗?也尝试不使用 async 属性。我不知道为什么这会解决它,但值得一试。

【讨论】:

  • 但是如何保存所有的 Promise,然后我可以将它们与 .when() 一起使用?
  • 我编辑了我的答案来举个例子
  • 感谢您的示例。在所有的 Promise 完成之前,它仍然会触发 templateDone,但我觉得它已经接近解决这个问题了。
  • 嗯,这很奇怪。 loadTemplate 里面的代码是什么样的?我猜它使用 $.ajax?
  • 是的,是的。我将使用 loadTemplate 的代码更新我的问题
【解决方案2】:

您可以编写简单的条件来检查是否所有模板都像这样加载

var loaded_template = 0;  
$.each(templates.hbs, function(idx, template) {
    loadTemplate(template.name)
      .then(function(templateStr){
        var compiledTemplate = Handlebars.compile(templateStr);
        if(template.isPartial){
          Handlebars.registerPartial(template.key, compiledTemplate);
        }
        templates[template.key] = compiledTemplate;
        loaded_template++;
        if(loaded_template == templates.hbs.length){
         foo();
        }
      });
  });

我希望这对你有用。即使您使用 ajax 调用加载模板,您也可以使用这种方法。如果您使用 ajax 加载模板,则在 $.each 之后调用函数将不起作用..

【讨论】:

  • 是的,这行得通。但是,我想知道是否有办法通过事件而不是计数器来做到这一点
  • 计数器是一种很好且有效的方法,正如我所说,如果你想加载模板,即使使用 ajax 调用。 $.each 函数没有回调事件,因此 $.each 完成时不会引发事件。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-04
  • 2019-02-22
  • 2021-03-24
  • 2016-09-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多