Есть ли такая вещь, как необязательный отсроченный? - PullRequest
2 голосов
/ 16 ноября 2011

Мне трудно понять, как написать этот блок кода ...

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 есть много зависимостей от остального кода выше.

Так что я подумал об использовании отложенного / обещания, но как я могу выполнить код как обещание, если 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 ]

3 голосов
/ 16 ноября 2011

Более простой подход - поместить функциональность кодового блока 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
  }
}
2 голосов
/ 16 ноября 2011

Вы всегда можете начать с фиктивного обещания:

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

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

Полагаю, это был твой основной вопрос, поэтому ответ "да" :-) Просто сделай свой. Конечно, вы можете определить его как глобальный сервис, если вы чувствуете, что это случится много.

Полагаю, вы могли бы также начать с легально сконструированного "отложенного" объекта, который вы немедленно разрешаете.

1 голос
/ 16 ноября 2011

Хотя я думаю, что мне больше нравится простота ответа lwburk, вы также можете создать свой собственный метод, который работает как отложенный метод.Это дает больше гибкости в более сложных ситуациях.См. jQuery Deferred Object для получения дополнительной информации о настройке, но здесь это с вашим примером:

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