繁体   English   中英

使用 Ajax 调用处理超时

[英]handlign timeout with Ajax call

我不是 JS 人(可以写一些基本的东西),我正在努力将我们的付款 API 与前端集成,作为该过程的一部分,我们想触发超时以防我的后端付款 API 没有响应在给定的时间范围内。 这是与付款 API 交互的 JS 代码。

performAuthorizePaymentRequest: function (payment) {
        return new Promise(function (resolve, reject) {
            $.ajax({
                type: 'POST',
                url: encodedContextPath + '/checkout/authorise_order',
                data: JSON.stringify(payment),
                dataType: 'json',
                contentType: 'application/json',
                success: resolve,
                error: reject,
                always: function () {
                     pageSpinner.end() 
                },
                timeout: 30000 /* call this.session.completePayment() within 30 seconds or the payment is cancelled */
            });
       });
    }

这似乎工作正常,但是我看到了以下问题。

  1. 如果 m 支持的 API 抛出任何错误,代码仍在等待超时。
  2. 即使对于成功案例,js 也会在显示成功消息之前等待超时。

有没有办法处理这个? 如果我在这里做错了什么,请告诉我。

注意:此代码只执行 Safari,其他浏览器不可用

您可以使用XMLHttpRequest object 的abort方法,然后设置超时以在 30 秒后中止请求。 像这样:

var requestObj = $.ajax({
    ...
)};
setTimeout(function(){
    requestObj.abort();
}, 30 * 1000); // 30 seconds

请参阅XMLHttpRequest.abort 参考


另一种方法是通过将状态标志设置为“超时”来让success的 function 在 30 秒后停止工作。 请参阅下面代码中的注释:

/* Use this variable to check whether we are within 30 minutes. This can be:
    'still in time': the original state, waiting for a response
    'out of time': we passed the 30 minutes, don't do anything with a possible success response and call the reject function
    'already resolved': resolved within 30 minutes, no need to reject after 30 minutes
*/
var timeStatus = 'still in time';
/* Time until timeout */
var timeoutTime = 30 * 1000; //30 seconds
/* Save the request */
var theRequest = $.ajax({
    ...
    /* In success we must check if we are still in time */
    success: function(data, textStatus, jqXHR){
        
        if(timeStatus === 'out of time'){
            // BAIL OUT. Do nothing since this has alreay been rejected in the setTimeout function. */
            console.log("bailing out. 30 minutes exceeded");
            return false;
        }
        else{
            /* Set to 'already resolved' so our setTimeout function doesn't reject. */
            timeStatus = 'already resolved';
            resolve(data, textStatus, jqXHR);
        }
    },
    /* In error we do the same 'out of time' check */
    error: function (jqXHR, errorCode, error){
        if(timeStatus === 'out of time'){
            // BAIL OUT. Do nothing since the request has alreay been rejected in the setTimeout function. */
            console.log("bailing out. 30 minutes exceeded");
            return false;
        }
        else{
            /* Set to 'already resolved' so our setTimeout function doesn't reject. */
            timeStatus = 'already resolved';
            reject(jqXHR, errorCode, error);
        }
    }
});
/* After 30 minutes set the timeStatus to 'out of time' so we can cut off incoming ajax responses. */
setTimeout(function(){
    if(timeStatus !== 'already resolved'){
        timeStatus = 'out of time';
        reject(theRequest, 'timeout','');
    }
}, timeoutTime); 

I would avoid a timeout in the ajax call, but would go to a with a set_time_limit(30) in the php (if your /checkout/authorise_order is a php...)

如果答案在之前到达,一切都很好(不会等到 30 秒)这是一个时间限制......

对于 javascript 部分,我使用自己的:

function ajaxLive ( divID ) {
    var pcache = (Math.floor(Math.random() * 100000000) + 1);
    var params = "divID="+encodeURIComponent(divID);
    var xhr = new XMLHttpRequest(); 
    xhr.open("POST", "path_to_script.php?pcache="+pcache, true);
    xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    xhr.onprogress = function(e) { if (xhr.readyState == 4) { $("#"+divID).html(e.currentTarget.responseText) ; } }
    xhr.send(params);
}

在这个 function pcache中,如果避免缓存至关重要,因为 api 调用的目的是每次都有不同的答案......

params中你也可以添加额外的东西,它会将它传递给 php

如果您使用 php curl 或 shell ZF6E57C9DE709E45FEB540D955351F 机制,还有最大时间机制,

curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 0); // for the connection (not the answer)
curl_setopt($ch, CURLOPT_TIMEOUT, 30); //timeout in seconds

你可以像这样中止超时吗? 这个例子有错误,但你可以在成功时做同样的事情

$.ajax({
url: "/your_ajax_method/",
type: "GET",
dataType: "json",
timeout: 3000, //Set your timeout value in milliseconds or 0 for unlimited
success: function(response) { alert(response); },
error: function(jqXHR, textStatus, errorThrown) {
    if(textStatus!=="timeout")  
          jqXHR.abort("timeout");    
}

});

我建议坚持使用 fetch 而不是 ajax 因为默认情况下它会在 300 秒后超时,并且如果服务器返回错误则会失败。

您还可以使用 abort controller https://developer.mozilla.org/en-US/docs/Web/API/AbortController在默认超时之前中止请求。

fetch 中的相同代码是:


const performAuthorizePaymentRequest = (payment) =>
  fetch(`${encodedContextPath}/checkout/authorise_order`, {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json'
    },
    body: JSON.stringify(payment), 
  }).then(r=>{
   pageSpinner.end();
   return r.json();
  })

performAuthorizePaymentRequest: function (payment) {

// you can start a loading on your view in here like this
// $('.fix-loading').show('fast');
      let promises_await = [];
      promises_await.push(
                    $.ajax({
                        type: 'POST',
                        url: encodedContextPath + '/checkout/authorise_order',
                        data: JSON.stringify(payment),
                        dataType: 'json',
                        contentType: 'application/json',
                        success: resolve,
                        error: reject,
// I don't know are these lines below are necessary for your payment or not
                        //always: function () {
                        //     pageSpinner.end() 
                        //},
                        //timeout: 30000 /* call this.session.completePayment() within 30 seconds or the payment is cancelled */
                    });
             );

$.when.apply($, promises_await).then(function () {
// if all requests in ajax complete and receive answer, do something here

// also if use loading you can hide it here like this and also in catch
// $('.fix-loading').hide('fast');
}).catch(function () {
// also if use loading you can hide it here like this and also in catch
// $('.fix-loading').hide('fast');
//error handling
});
}

您可以使用 promise.race()。

Promise.race() 方法返回一个 promise,一旦可迭代中的一个承诺履行或拒绝,就会履行或拒绝,其值或原因来自该 promise。

例子:

const timeout = (prom, time) =>
    Promise.race([prom, new Promise((_r, rej) => setTimeout(rej, time))]);

利用:

// resolves in 500 ms
const fn = async () => {
    await new Promise((res) => setTimeout(res, 500));
    return "p2";
}

// finishes before the timeout
const result = await timeout(fn(), 1000);
// result = p2

// timeouts in 100 ms
await timeout(fn(), 100);
// error

参考: 匿名棒。com

  • 我会建议你一些我不知道你是否会喜欢它或者是否适合你的东西,但是你可以使用setInterval()方法,这个方法会自动重复你的代码很多次,如果事件发生停止,你可以创建一个条件这个setInterval() function

例子

    var check = false;
    setInterval(function() {
        if (check === true) {
            return;
        }
        $.ajax({
            type: 'POST',
            url: encodedContextPath + '/checkout/authorise_order',
            data: JSON.stringify(payment),
            dataType: 'json',
            contentType: 'application/json',
            success: function(e) {
                if (e.status === 200) {
                    check = true;
                }
            },
            always: function() {
                pageSpinner.end()
            }
        });
    }, 10);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM