skip to Main Content

I’m working with a JS API that I access by using POSTs and GETs. It’s for an e-comm platform (Shopify), but I don’t believe this issue is related to the platform.

I’ve been able to write two POST requests that individually perform exactly as needed whether in code, or in the console. However, I simply cannot get them to fire one after the other (the first must complete before the second begins in my case).

The first request is as follows (this clears the cart, and no data needs to be sent, just the URL needs to be POSTed to):

  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);
     }
    });
  }

The second request is as follows (this adds a certain item and a certain quantity of said item to the cart, then redirects to checkout):

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);
     }
    });
  }

The way that I’m chaining them together looks like this (variables are populated correctly):

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

After much testing, I sometimes seem to have the code work correctly (maybe 1/10th of the time) so I’m led to believe it is a timing issue, although I can’t say for certain as I can’t consistently test to those results.

My only real clue is that the functions individually work when I use .done(), but when I use .success(), they return the following:

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)

Any help?

Update
I’m actually able to resolve the syntax error by explicitly specifying a datatype of ‘json’. Regardless, the two functions still behave erratically, only working in the right order sometimes.

5

Answers


  1. If your assessment is correct, you can simply make the functions run synchronously in order to ensure that your second function is called only when the first one has executed. Here’s how you could do it:

      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);
         }
        });
      }
    

    Note the async property that tells the browser to wait for the request to complete before next function is called. You do not need to set this on the second function given that you are not expecting anything to execute after that.

    Also, I would suggest you use a callback in the first function rather than async=false as async tends to hurt user experience.

    Reference: http://api.jquery.com/jquery.ajax/

    Login or Signup to reply.
  2. No value or jQuery promise is returned from either clearCart() or cartAdd() functions, see Why is value undefined at .then() chained to Promise?. return the $.ajax() call, chain .then() to call second function.

    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);
    
    Login or Signup to reply.
  3. The problem of putting async option is that this option makes everything hanging until the response.

    For these cases: at first we call the ajaxes on the ready function of page and put them in different sessionStorage s and then in our function (which will be out of ready or at least the function is out of ready and just call it in ready) we check the values. If they are null we call the function again after a specific time (3s for example) usning setTimeout and after a while the values are set and we can use them in our function

    Example code:

    $(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
    }
    

    And by the way, sessionStorage is diffrent for each browser and if the current window is closed you can’t, you have to set it again. If you want to use something like that but have access from all browser window (which your site is open in them) use localStorage instead of sessionStorage

    Login or Signup to reply.
  4. Return promise to make it use like chaining.

      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
         }
        });
      }
    

    Now call function like this

      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
      })
    
    Login or Signup to reply.
  5. There are other ways instead of using deprecated method “async: false”. As sometimes it may result badly. However, you can use it.
    But I would suggest you other ways to achieve this task:

    First: Use deferred.then() method
    for example if you have two ajax calls:

      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 just use then method and return second ajax call as promise :

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

    It will result what you expected or chaining of ajax Calls.

    Another method is just put the ajax calls inside the success block of ajax.

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

    Both methods will result what you expected and the good thing about them is they are not the deprecated method.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search