php - 使用 JS setTimeout 在循环中发布 AJAX 请求,但 setTimeout 被调用得太频繁了

标签 php javascript ajax

这个问题已经回答了。问题是 myEventMoveTrainManaul() 是从代码中的其他位置调用的。感谢所有提供帮助的人。

请原谅我重新发布这篇文章,但它几乎没有引起人们的注意,找到有人帮助我解决这个问题非常重要。感谢您的理解。

我一直在为我编写的 Facebook 游戏开发一项新功能。该游戏允许玩家乘坐火车在欧洲城市之间穿梭并运送 cargo 以获取利润。我添加的这个功能为游戏添加了寻路 AI:它允许玩家选择要前往的城市,然后游戏会自动将玩家的火车沿着轨道从起点城市移动到目的地城市。我正在使用 AJAX 和 setTimeout() 从后端获取数据并使火车沿着连接城市的轨道行驶。请引用代码,它(希望)包含对我正在尝试做的事情的更好理解。

问题是 setTimeout() 被调用得太频繁了。我放置了一个名为 statusFinalDest 的全局变量,它可能包含两个值:ENROUTE 和 ARRIVED。当火车正在 ENROUTE 时,JS 火车运动函数使用 setTimeout 调用自身,直到后端返回 statusFinalDest ARRIVED,此时火车运动超时循环(应该)终止。但是,它不是为后端进程的每个回合调用一次 myEventMoveTrainManual(),而是被调用得非常频繁,就好像它没有识别 statusFinalDest 的更改状态一样。我试图在代码中加入更多的限制结构来结束这种过度行为,但它们似乎不起作用。

仅供引用 - 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() 被调用了太多次。

最佳答案

你需要你的 setTimeout 在你的 ajax 调用的回调中(ajax.onDone 如果我没看错的话)

我假设您希望仅在第一次调用完成后才再次调用您的 ajax 调用。目前,此代码将每秒执行一次您的函数,与挂起的异步调用无关。

这是你想要的吗?或者你想让它在你的 ajax 返回后一秒钟执行吗?如果是后者,请将您的 setTimeout 放在该回调中,您只会在 ajax 返回后的 1 秒内收到下一个请求。

编辑调整示例:

我仍然没有在 ajax 调用中看到您的 setTimeout。这是一些伪代码和解释:

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 返回时,您可以做任何您想做的事情,然后在 x 毫秒后(在 onDone 内)再次调用 myFunc()(setTimeout)。这会实例化您的 ajax 对象并进行调用...

关于php - 使用 JS setTimeout 在循环中发布 AJAX 请求,但 setTimeout 被调用得太频繁了,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3347093/

相关文章:

javascript - 如何从在线可视化中获取 CSV?

asp.net - 加快 Web 服务的自动完成速度并避免过多的方法调用

javascript - 使用本地 AJAX 请求解析 JSON 数据

php - 设置 javascript 变量时包含 PHP 文件

php - MySql/php - 标签系统

javascript - jQuery Ajax 从 php 返回一些值

javascript - 通过正则表达式删除标签符号 js

php - 在 ajax 输出上显示未定义值的选项列表

php - 使用 WAMP/PHP 5.3.4 时出现 MSSQL 错误(表示未启用)

java - 使用堆栈交换 API