jQuery Ajax设置3秒Timeout无效,Deferred仍等待PHP300秒超时
问题原因
你设置的jQuery Ajax timeout没生效,是因为前端的超时是检测“服务器是否在指定时间内返回响应”,但你的PHP脚本一直在后台运行(直到触发自身300秒的max_execution_time错误),期间没有断开连接,所以客户端会一直等服务器输出,不会触发前端的超时。
PHP默认在脚本执行完之前不会向浏览器输出任何内容,连接处于“挂起”状态,jQuery没法判断服务器是不是在干活,只会傻等直到服务器返回结果(不管是成功还是致命错误)。
解决办法
1. 核心优化:后端分批处理(必须做)
批量地理编码本来就不该一次性处理大量地址,不仅容易超时,还会占用服务器资源。正确的做法是拆分任务:
- 后端
ajax.php接受page和limit参数,每次只处理N条地址(比如10条) - 前端循环发送请求,每次处理完一批再请求下一批,直到所有地址处理完成
前端修改代码
function initialize() { var map; var bounds = new google.maps.LatLngBounds(); var mapOptions = { mapTypeId: 'roadmap' }; map = new google.maps.Map(document.getElementById("mappa"), mapOptions); var infoWindow = new google.maps.InfoWindow(), marker, i; // 分批加载,初始页码1,每页10条 loadLocationsByPage(1, 10, map, bounds); } function loadLocationsByPage(page, limit, map, bounds) { $.ajax({ url: 'ajax.php', dataType: 'json', data: {page: page, limit: limit}, timeout: 10000 // 单批处理耗时短,设置10秒足够 }).done(function (result) { // 渲染当前批的标记 result.data.forEach(item => { var position = new google.maps.LatLng(item.lat, item.lng); bounds.extend(position); new google.maps.Marker({ position: position, map: map, title: item.nome }); }); // 如果还有下一页,继续请求 if (result.hasMore) { loadLocationsByPage(page + 1, limit, map, bounds); } else { // 所有数据加载完成,调整地图视野 map.fitBounds(bounds); } }).fail(function() { $.alert(`第${page}页加载超时,请重试`); }); } google.maps.event.addDomListener(window, 'load', initialize);
后端ajax.php修改示例
<?php // 单批处理不需要太长执行时间,设置为60秒足够 ini_set('max_execution_time', 60); $page = $_GET['page'] ?? 1; $limit = $_GET['limit'] ?? 10; $offset = ($page - 1) * $limit; // 替换成你的地址查询逻辑,比如从数据库取当前页的地址 $addresses = getAddressesFromDb($offset, $limit); $latlngData = []; foreach ($addresses as $addr) { // 调用地理编码API获取经纬度 $latlng = geocodeAddress($addr['address']); if ($latlng) { $latlngData[] = [ 'lat' => $latlng['lat'], 'lng' => $latlng['lng'], 'nome' => $addr['nome'] ]; } } // 判断是否还有更多数据 $total = getTotalAddressesCount(); $hasMore = ($page * $limit) < $total; echo json_encode([ 'data' => $latlngData, 'hasMore' => $hasMore ]); ?>
2. 前端手动强制超时(应急用)
如果暂时没法改后端,要让前端在3秒后直接触发失败,可以自己封装Deferred,结合setTimeout手动中断请求:
function loadLocations() { var deferred = $.Deferred(); var xhr = $.ajax({ url: 'ajax.php', dataType: 'json' }); // 手动设置3秒超时 var timeoutId = setTimeout(function() { xhr.abort(); // 中断请求 deferred.reject('timeout'); }, 3000); xhr.done(function(data) { clearTimeout(timeoutId); deferred.resolve(data); }).fail(function() { clearTimeout(timeoutId); deferred.reject(); }); return deferred.promise(); }
这个方法会在3秒后主动中断请求,触发fail回调,但后端脚本还是会在服务器上继续跑直到超时,只是前端不等了。
3. 临时调整PHP超时(不推荐)
如果只是测试,可以在ajax.php开头临时延长执行时间,但这不是长久之计:
<?php ini_set('max_execution_time', 600); // 设置为600秒(10分钟) // 或者用set_time_limit(600); ?>
内容的提问来源于stack exchange,提问作者itajackass
相关产品推荐
相关产品推荐

