无法按顺序触发两个 jQuery ajax 调用

Posted

技术标签:

【中文标题】无法按顺序触发两个 jQuery ajax 调用【英文标题】:Cannot get two jQuery ajax calls to fire in order 【发布时间】:2017-07-15 03:33:49 【问题描述】:

我正在使用通过 POST 和 GET 访问的 JS API。这是针对电子商务平台(Shopify)的,但我认为这个问题与平台无关。

我已经能够编写两个 POST 请求,无论是在代码中还是在控制台中,它们都可以根据需要单独执行。但是,我根本无法让他们一个接一个地触发(在我的情况下,第一个必须在第二个开始之前完成)。

第一个请求如下(这样清了购物车,不需要发送任何数据,只需要 POST 到的 URL):

  function clearCart()
    $.ajax(
      url: '/cart/clear.js',
      method: 'POST',
      success: function()
        console.log("cleared");  
      ,
     error: function(jqXHR, textStatus, errorThrown) 
          console.log('jqXHR:');
          console.log(jqXHR);
          console.log('textStatus:');
          console.log(textStatus);
          console.log('errorThrown:');
          console.log(errorThrown);
     
    );
  

第二个请求如下(将某商品和该商品的一定数量添加到购物车,然后重定向到结帐):

function cartAdd(quantity, id)
    $.ajax(
      url: '/cart/add.js',
      method: 'POST',
      data: 
        quantity: quantity,
        id: id
      ,
      success: function(data)
        console.log("added");
        window.location.href = '/checkout';
      ,
      error: function(jqXHR, textStatus, errorThrown) 
          console.log('jqXHR:');
          console.log(jqXHR);
          console.log('textStatus:');
          console.log(textStatus);
          console.log('errorThrown:');
          console.log(errorThrown);
     
    );
  

我将它们链接在一起的方式如下所示(变量填充正确):

$.when(
    clearCart(),
    cartAdd(variantQuantity, variantID)
);

经过大量测试,我有时似乎让代码正常工作(可能是 1/10 的时间),所以我被引导相信这是一个时间问题,尽管我不能肯定地说t 始终如一地测试这些结果。

我唯一真正的线索是,当我使用 .done() 时,这些函数单独工作,但是当我使用 .success() 时,它们返回以下内容:

SyntaxError: Unexpected token :
    at eval (<anonymous>)
    at jquery-1.10.2.min.js?1013630…:4
    at Function.globalEval (jquery-1.10.2.min.js?1013630…:4)
    at text script (jquery-1.10.2.min.js?1013630…:6)
    at On (jquery-1.10.2.min.js?1013630…:6)
    at k (jquery-1.10.2.min.js?1013630…:6)
    at XMLHttpRequest.r (jquery-1.10.2.min.js?1013630…:6)

有什么帮助吗?

更新 我实际上可以通过明确指定“json”的数据类型来解决语法错误。无论如何,这两个函数的行为仍然不稳定,有时只能以正确的顺序工作。

【问题讨论】:

您不能按照这个答案在success 响应中调用addCart() 吗? ***.com/questions/10089447/… 【参考方案1】:

如果您的评估是正确的,您可以简单地使函数同步运行,以确保仅在第一个函数执行后才调用您的第二个函数。你可以这样做:

  function clearCart()
    $.ajax(
      url: '/cart/clear.js',
      method: 'POST',
      async: false,
      success: function()
        console.log("cleared");  
      ,
     error: function(jqXHR, textStatus, errorThrown) 
          console.log('jqXHR:');
          console.log(jqXHR);
          console.log('textStatus:');
          console.log(textStatus);
          console.log('errorThrown:');
          console.log(errorThrown);
     
    );
  

注意async 属性告诉浏览器在调用下一个函数之前等待请求完成。您不需要在第二个函数上设置它,因为您不希望在那之后执行任何操作。

另外,我建议您在第一个函数中使用回调而不是 async=false,因为异步往往会损害用户体验。

参考:http://api.jquery.com/jquery.ajax/

【讨论】:

完美运行。非常感谢。【参考方案2】:

clearCart()cartAdd() 函数没有返回值或 jQuery 承诺,请参阅 Why is value undefined at .then() chained to Promise?。 return$.ajax() 调用,链接.then() 调用第二个函数。

function clearCart() 
  return $.ajax(
    url: '/cart/clear.js',
    method: 'POST'
  );


function cartAdd(quantity, id) 
  return $.ajax(
    url: '/cart/add.js',
    method: 'POST',
    data: 
      quantity: quantity,
      id: id
    
  )


function handleError(jqXHR, textStatus, errorThrown) 
  console.log('jqXHR:');
  console.log(jqXHR);
  console.log('textStatus:');
  console.log(textStatus);
  console.log('errorThrown:');
  console.log(errorThrown);



clearCart()
  .then(function() 
    console.log("cleared")
    return cartAdd(variantQuantity, variantID)
  )
  .then(function() 
    console.log("added");
    window.location.href = '/checkout';
  )
  .fail(handleError);

【讨论】:

这是一种方法【参考方案3】:

返回承诺使其像链接一样使用。

  function clearCart() 
    return $.ajax(
      url: '/cart/clear.js',
      method: 'POST',
      success: function() 
        console.log("cleared");
      ,
      error: function(jqXHR, textStatus, errorThrown) 
                // error handler
      
    );
  

  function cartAdd(quantity, id)
    return $.ajax(
      url: '/cart/add.js',
      method: 'POST',
      data: 
        quantity: quantity,
        id: id
      ,
      success: function(data)
        console.log("added");
        window.location.href = '/checkout';
      ,
      error: function(jqXHR, textStatus, errorThrown) 
                // error handler
     
    );
  

现在像这样调用函数

  clearCart().done( function()
    // after cart is empty, code goes below

    // Example code to add item to cart
    cartAdd( 3, 1);

  ).fail(function()

    // clear cart failed
    // put handler here if required
  )

【讨论】:

如果您需要使用 .done 和 .always,这是最好的方法【参考方案4】:

async选项的问题是这个选项让一切都挂起,直到响应。

对于这些情况:首先我们在页面的ready 函数上调用ajax,并将它们放在不同的sessionStorage s 中,然后在我们的函数中(将在ready 之外或至少该函数是从ready 中调用它并在ready 中调用它)我们检查值。如果它们为空,我们会在特定时间(例如 3 秒)后再次调用函数,使用 setTimeout 并在一段时间后设置值,我们可以在函数中使用它们

示例代码:

$(document).ready(function()
    sessionStorage.setItem("firstApi",JSON.stringify(callFirstAjax()));
    sessionStorage.setItem("secondApi",JSON.stringify(callSecondAjax()));

    doSomething();
);

function doSomething() 
    var firstApi = sessionStorage.get("firstApi");
    var secondApi = sessionStorage.get("secondApi");
    if(firstApi == null || secondApi == null) 
        setTimeout(function() 
            firstApi = null;
            secondApi = null;
            doSomething();
         , 3000);
    
    // rest of function based on two variable values

顺便说一下,每个浏览器的 sessionStorage 是不同的,如果当前窗口关闭你不能,你必须重新设置它。如果您想使用类似的东西,但可以从所有浏览器窗口(您的网站在其中打开)访问,请使用 localStorage 而不是 sessionStorage

【讨论】:

【参考方案5】:

还有其他方法可以代替使用已弃用的方法“async: false”。因为有时它可能会导致糟糕的结果。但是,您可以使用它。 但我会建议你用其他方法来完成这项任务:

首先:使用 deferred.then() 方法 例如,如果您有两个 ajax 调用:

  function clearCart()
   $.ajax(
   url: '/cart/clear.js',
   method: 'POST',
   .... );
  

  function cartAdd(quantity, id)
   $.ajax(
   url: '/cart/add.js',
   method: 'POST',
   data: 
     quantity: quantity,
     id: id
   ,
   .....);
 

然后只需使用 then 方法并返回第二个 ajax 调用作为承诺:

$.when(clearCart(....)).then(function() return cartAdd(....));

这将导致您期望的结果或 ajax 调用的链接。

另一种方法是将ajax调用放在ajax的成功块中。

function clearCart()
   $.ajax(
   url: '/cart/clear.js',
   method: 'POST',
   success: function(data)
      cartAdd(....);
   
   ...... );
  

这两种方法都会产生您所期望的结果,而且它们的好处是它们不是已弃用的方法。

【讨论】:

以上是关于无法按顺序触发两个 jQuery ajax 调用的主要内容,如果未能解决你的问题,请参考以下文章

当从同一个组件调用时,两个 IBAction 触发的顺序是啥?

jQuery中Ajax事件顺序及各参数含义

无法从 JQuery ajax 调用接收 JSON

对 .NET WebMethod 的 jQuery 调用无序运行

ajax调用后Jquery事件不会触发

当 jQuery ajax 调用开始时,loadmask 没有触发