是否存在可选延期的事情?

时间:2011-11-16 19:09:38

标签: javascript jquery jquery-deferred

我很难弄清楚如何编写这段代码......

function myFunction(x,y,z) {
  // do some stuff here (code block A)

  // then some stuff here (code block B)

  // but... 
  if (y == 73) { // y isn't always 73...
    // I need more data from the server before I can complete this function
    $.getJSON("data.php", {y: 73, z: z}, function(data) { ... });
  }

  // and finally some other code down here (code block C)

  // And done!
  $.post("data.php", {data: someVariable}, callbackFx);
}

所以我遇到的概念问题是,在我意识到需要从服务器获取更多来自给定输入的数据后,我想要执行代码(代码块C)。它不会一直发生,但我基本上想暂停执行。我们都知道同步AJAX是一种犯罪行为,可以通过Javascript神的鞭打来惩罚。

起初我认为代码块C应该只是进入它自己的函数,但它会变得混乱,因为在上面的其余代码中代码块C中存在许多依赖关系。

所以我考虑使用deferred / promise,但是如果AJAX并不总是必然发生的话,如何将代码作为承诺执行呢?

if (y == 73) {
  var deferred = $.getJSON("data.php", {y: 73, z: z}, function(data) { ... });
  deferred.always(function() { ... });
}
else {
  // that function in the deferred never gets called
}

我能想到的最接近“好答案”的是以下(但我不知道它是否真的是一个“好的答案”)......

var codeBlockC = function() { ... };

if (y == 73) {
  var deferred = $.getJSON("data.php", {y: 73, z: z}, function(data) { ... });
  deferred.always(codeBlockC);
}
else {
  codeBlockC();
}

然后存在范围和闭包以及东西的问题。有任何想法吗?我只需要完全重新组织我的方式吗?

3 个答案:

答案 0 :(得分:3)

更简单的方法是将代码块C 的功能放在嵌套函数中。 JavaScript具有词法范围,因此所有需要的数据仍然可用。

例如:

function myFunction(x,y,z) {
  // do some stuff here (code block A)

  // then some stuff here (code block B)

  var codeBlockC = function() {
      // code in here can access all variables from code blocks A and B
      // everything after the potential Ajax call needs to be in here

      // and finally some other code down here (code block C)

      // And done!
      $.post("data.php", {data: someVariable}, callbackFx);
  };

  // but... 
  if (y == 73) { // y isn't always 73...
    // I need more data from the server before I can complete this function
    $.getJSON("data.php", {y: 73, z: z}, function(data) { 
        codeBlockC(); // execute as callback
    });
  } else {
      codeBlockC(); // execute immediately
  }
}

答案 1 :(得分:2)

你总是可以从假承诺开始:

var def = { always: function(f) { f(); } };
if (whatever) {
  def = $.get( ... whatever ... );
}

def.always(function() {
  $.post( ... whatever ... );
}

我想这就是你的基本问题,所以答案是肯定的:-)只做自己的。当然,如果您觉得它会发生很多事情,您可以将其定义为全球服务。

我想你也可以从一个合法构造的“延期”对象开始,你可以立即解决它。

答案 2 :(得分:1)

虽然我认为我更喜欢lwburk答案的简单性,但您也可以创建自己的方法作为延迟方法。这为更复杂的情况提供了更多的灵活性。有关设置的信息,请参阅jQuery Deferred Object for more info,但这里是您的示例:

function myFunction(x,y,z) {
    var deferredFunction;

    // do some stuff here (code block A)

    // then some stuff here (code block B)

     //define your own function that is deferred
    deferredFunction = function () { 
        var defer = $.Deferred(); 

        if (y == 73) {
            $.getJSON("data.php", {y: 73, z: z}, function(data) { 

                //your code... 

                defer.resolve();
            });
        } else {
            defer.resolve();
        }

        return defer.promise();
    }

    //now execute the your function and when it resolves execute the rest of the code
    deferredFunction().then(function () {

         // and finally some other code down here (code block C)

         // And done!
         $.post("data.php", {data: someVariable}, callbackFx);
    });
}