Использование JS setTimeout для отправки AJAX-запросов в цикле, но setTimeout вызывается слишком часто - PullRequest
2 голосов
/ 27 июля 2010

На этот вопрос ответили. Проблема заключалась в том, что myEventMoveTrainManaul () вызывался из других мест в коде. Спасибо всем, кто предложил свою помощь.

Пожалуйста, прости меня за повторную публикацию, но на это почти не обращали внимания, и очень важно, чтобы я нашел кого-то, кто поможет мне с этим. Благодарим Вас за понимание.

Я работаю над новой функцией для игры на Facebook, которую я написал. Игра позволяет игроку путешествовать между городами Европы на поезде и доставлять товары для получения прибыли. Эта функция, которую я добавляю, добавляет AI к поиску пути: она позволяет игроку выбрать город для поездки, а затем игра автоматически перемещает поезд игрока по дорожке из его стартового города в город назначения. Я использую AJAX и setTimeout (), чтобы получить данные из бэкэнда и включить движение поезда по пути, соединяющему города. Пожалуйста, обратитесь к коду, который (надеюсь) будет содержать лучшее понимание того, что я пытаюсь сделать.

Проблема в том, что setTimeout () вызывается слишком часто. Я поместил глобальную переменную с именем statusFinalDest, которая может содержать два значения: ENROUTE и ARRIVED. Пока поезд находится в состоянии ENROUTE, функция движения поезда JS вызывает себя, используя setTimeout, пока бэкэнд не вернет statusFinalDest из ARRIVED, и в этот момент цикл ожидания движения поезда (предположительно) будет (предположительно) завершен. Однако вместо того, чтобы вызывать myEventMoveTrainManual () один раз для каждого хода бэкэнд-процессов, он вызывается очень часто, как будто он не распознает измененное состояние statusFinalDest. Я попытался поместить в код больше ограничивающих структур, чтобы положить конец этому чрезмерному поведению, поскольку они, похоже, не работают.

FYI - myEventMoveTrainManual () не является обработчиком событий, но он вызывается из обработчика событий.

Вот соответствующий код FBJS (Facebook JS):

function myEventMoveTrainManual(evt) {
      if(mutexMoveTrainManual == 'CONTINUE') {
        //mutexMoveTrainManual = 'LOCKED';
        var ajax = new Ajax();
        var param = {};
        if(evt) {
          var cityId = evt.target.getParentNode().getId();
          var param = { "city_id": cityId };
        }
        ajax.responseType = Ajax.JSON;
        ajax.ondone = function(data) {
          statusFinalDest = data.status_final_dest;
          if(data.code != 'ERROR_FINAL_DEST') {

            // Draw train at new location
            trackAjax = new Ajax();
            trackAjax.responseType = Ajax.JSON;
            trackAjax.ondone = function(trackData) {
              var trains = [];
              trains[0] = trackData.train;
              removeTrain(trains);
              drawTrack(trackData.y1, trackData.x1, trackData.y2, trackData.x2, '#FF0', trains);

              if(data.code == 'UNLOAD_CARGO') {
                unloadCargo();
              } else if (data.code == 'MOVE_TRAIN_AUTO' || data.code == 'TURN_END') {
                moveTrainAuto();
              } else {
                /* handle error */
              }
              mutexMoveTrainManual = 'CONTINUE';
            }
            trackAjax.post(baseURL + '/turn/get-track-data');
          }
        }
        ajax.post(baseURL + '/turn/move-train-set-destination', param);
      }

      // If we still haven't ARRIVED at our final destination, we are ENROUTE so continue
      // moving the train until final destination is reached
      // statusFinalDest is a global var
      if(statusFinalDest == 'ENROUTE') {
        setTimeout(myEventMoveTrainManual, 1000);
      }
}

А вот бэкэнд-код PHP:

  public function moveTrainSetDestinationAction() {
    require_once 'Train.php';
    $trainModel = new Train();

    $userNamespace = new Zend_Session_Namespace('User');
    $gameNamespace = new Zend_Session_Namespace('Game');

    $this->_helper->layout()->disableLayout();
    $this->_helper->viewRenderer->setNoRender();

    $trainRow = $trainModel->getTrain($userNamespace->gamePlayerId);
    $statusFinalDest = $trainRow['status_final_dest'];
    if($statusFinalDest == 'ARRIVED') {
      $originCityId = $trainRow['dest_city_id'];
      $destCityId = $this->getRequest()->getPost('city_id');
      if(empty($destCityId)) {
        // If we arrived at final dest but user supplied no city then this method got called
        // incorrectly so return an error
        echo Zend_Json::encode(array('code' => 'ERROR_FINAL_DEST', 'status_final_dest' => $statusFinalDest));
        exit;
      }

      $gameNamespace->itinerary = $this->_helper->getTrainItinerary($originCityId, $destCityId);
      array_shift($gameNamespace->itinerary); //shift-off the current train city location
      $trainModel->setStatusFinalDest('ENROUTE', $userNamespace->gamePlayerId);
      $statusFinalDest = 'ENROUTE';
    }
    $cityId = $trainRow['dest_city_id'];
    if($trainRow['status'] == 'ARRIVED') {
      if(count($gameNamespace->itinerary) > 0) {
        $cityId = array_shift($gameNamespace->itinerary);
      }
    }
    $trainRow = $this->_helper->moveTrain($cityId);
    if(count($trainRow) > 0) {
      if($trainRow['status'] == 'ARRIVED') {
        // If there are no further cities on the itinerary, we have arrived at our final destination
        if(count($gameNamespace->itinerary) == 0) {
          $trainModel->setStatusFinalDest('ARRIVED', $userNamespace->gamePlayerId);
          $statusFinalDest = 'ARRIVED';
        }
        echo Zend_Json::encode(array('code' => 'UNLOAD_CARGO', 'status_final_dest' => $statusFinalDest));
        exit;
        // Pass id for last city user selected so we can return user to previous map scroll postion
      } else if($trainRow['track_units_remaining'] > 0) {
        echo Zend_Json::encode(array('code' => 'MOVE_TRAIN_AUTO', 'status_final_dest' => $statusFinalDest));
        exit;
      } else { /* Turn has ended */
        echo Zend_Json::encode(array('code' => 'TURN_END', 'status_final_dest' => $statusFinalDest));
        exit;
      }
    }
    echo Zend_Json::encode(array('code' => 'MOVE_TRAIN_AUTO_ERROR'));
  }

Основываясь на предложении @ brad, я изменил myEventMoveTrainManual () следующим образом:

function myEventMoveTrainManual(evt) {
//debugger;
      if(mutexMoveTrainManual == 'CONTINUE') {
        //mutexMoveTrainManual = 'LOCKED';
        //statusFinalDest = 'ARRIVED';
        var ajax = new Ajax();
        var param = {};
        if(evt) {
          var cityId = evt.target.getParentNode().getId();
          var param = { "city_id": cityId };
        }
        ajax.responseType = Ajax.JSON;
        ajax.ondone = function(data) {

          statusFinalDest = data.status_final_dest;
//debugger;
consoleLog('statusFinalDest='+statusFinalDest+', data.code='+data.code);
          if(data.code != 'ERROR_FINAL_DEST') {
consoleLog('data.code != ERROR_FINAL_DEST');
            // Draw train at new location
            trackAjax = new Ajax();
            trackAjax.responseType = Ajax.JSON;
            trackAjax.ondone = function(trackData) {
consoleLog('drawing track');
              var trains = [];
              trains[0] = trackData.train;
              removeTrain(trains);
              drawTrack(trackData.y1, trackData.x1, trackData.y2, trackData.x2, '#FF0', trains);
consoleLog('processing data.code = '+data.code);
              if(data.code == 'UNLOAD_CARGO') {
                unloadCargo();
  consoleLog('returned from unloadCargo()');
              } else if (data.code == 'MOVE_TRAIN_AUTO' || data.code == 'TURN_END') {
                moveTrainAuto();
  consoleLog('returned from moveTrainAuto()');
  /*
              } else if (data.code == 'TURN_END') {
  consoleLog('moveTrainManual::turnEnd');
                turnEnd();
  */
              } else {
                /* handle error */
              }
              mutexMoveTrainManual = 'CONTINUE';

              // If we still haven't ARRIVED at our final destination, we are ENROUTE so continue
              // moving the train until final destination is reached
              if(statusFinalDest == 'ENROUTE') {
                myEventMoveTrainManual(null);
              }
            }
            trackAjax.post(baseURL + '/turn/get-track-data');
          }
        }
        ajax.post(baseURL + '/turn/move-train-set-destination', param);
      }

      // If we still haven't ARRIVED at our final destination, we are ENROUTE so continue
      // moving the train until final destination is reached
      //if(statusFinalDest == 'ENROUTE') {
      //  clearTimeout(timerId);
      //  timerId = setTimeout(myEventMoveTrainManual, 1000);
      //}
}

Однако первоначальная проблема все еще проявляется: myEventMoveTrainManual () вызывается слишком много раз.

Ответы [ 3 ]

0 голосов
/ 27 июля 2010

Ваши Ajax-вызовы асинхронны.Я думаю, что даже если серверная часть готова, ответу нужно время, чтобы вернуться к клиенту.Тем временем клиент отправляет больше Ajax-запросов.
(правка: Ваши изменения подтверждают, что это не проблема)

  • похоже, что вы зарегистрировали прослушиватель событий для DOM-событиякак щелчок мышью, потому что вы проверяете аргумент evt.Пожалуйста, отправьте код вашего обработчика события и часть кода, где вы регистрируете событие.

  • Кто сказал, что слишком много звонков?Я не вижу счетные переменные в скриптах сервера / клиента;Обратите внимание, что элементы журнала иногда добавляются в консоль слишком поздно, они не являются показателем для моих глаз.Я думаю, что очень важно знать ваши показатели!

0 голосов
/ 27 июля 2010

вам нужно, чтобы ваш setTimeout находился в обратном вызове вашего ajax-вызова (ajax.onDone, если я правильно читаю)

Я предполагаю, что вы хотите, чтобы ваш вызов ajax снова вызывался только после завершения первого вызова. В настоящее время этот код будет выполнять вашу функцию раз в секунду, независимо от ожидающих асинхронных вызовов.

Это то, что вы хотите? Или вы хотите, чтобы он был выполнен через одну секунду после того, как ваш ajax вернется? Если последнее, поместите ваш setTimeout в этот обратный вызов, и вы получите следующий запрос только 1 с после того, как ваш ajax вернется.

edit с настроенным примером:

Я до сих пор не вижу ваш setTimeout в вызове ajax. Вот некоторый псевдокод и объяснение:

function myFunc(){

  var ajax = new Ajax();
  ajax.onDone = function(data){
    // do some stuff here (ie modify mutex)

    // now trigger your setTimeout within this onDone to call myFunc() again:
    setTimeout(myFunc,1000);
  }

  ajax.post("someURL")
}

Объяснение Вот что происходит, вы вызываете myFunc (), он создает экземпляр вашего ajax-объекта и выполняет вызов. Когда этот ajax возвращается, вы делаете все, что хотите, а затем снова вызываете myFunc () (setTimeout) через x миллисекунд (внутри onDone). Это создает экземпляр вашего ajax-объекта и делает вызов ...

0 голосов
/ 27 июля 2010

Я не уверен в коде, но проблема выглядит так:

Вы проверяете, если statusFinalDest == 'ENROUTE' на стороне клиента, что не работает.

Поместите счетчик, основанный на таймере, на стороне сервера, прежде чем устанавливать глобальное значение в значение ENROUT, и не устанавливать его каждый раз, т. Е. Устанавливать задержку в 1 секунду для установки значения, так как любой метод на стороне клиента будет переопределен свежей копией js код.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...