When .always is not always

Photo by Greg Rakozy on Unsplash

When .always is not always

...or .always first

Hey devs. Today I came across a small defect that needed a small attention. This time it was located inside a javascript file so why not to mention it.

What's the problem.

So we had an issue that the loading wheel was spinning forever. Nothing tragic. You go, open the console and you'll see some crazy exception coming form jQuery. Ok so you pretty quickly found something crazy that was called inside finished ajax request. You then fix it and push it to git for testing round. Task done.

Aha moment.

Then you realize that the spinning wheel cancellation is inside a .done promise callback. So when there is a fail it spins forever. Ok, so you think about it and refactor the code a bit. First that came to my mind is to use the fail() and always() callbacks. I'll just place the cancellation to .always callback and the user will never be trapped. So I implemented this solution and start to test it. But the always was not executed. Why...?

So you start to dig deeper to find what's going on.

You know that in javascript world when there is some bug it stops the execution at that line so nothing else will be done. But the confusion comes to you when you start to execute something asynchronously. Something like an ajax request. Then you think that once the ajax request was done all the promises will be executed no matter if one of them will fail... And that's not true.

So I made a simple bug that will prevent you to finish the .done processing. And as you can see .always after it will not be executed.

  $.post('/echo/json','json={"hello":"world"}')
  .done(()=>{
    console.log('done');
    let objData = JSON.parse('bug');
  })
  .always(()=>{
    console.log('always');
  })
  .fail(()=>{
    console.log('fail');
  })
  console.log('continue');

Lessons learned

So whenever you want to finish some job/animation do it before the data processing. The solution is to execute the .always callback before the .done, .fail callbacks. That way the user will not be trapped in a blurred window with spinning whatever. Unless, you want them to be trapped...

//solution
$.ajax().always().done()...

FYI from jQuery help:

Promise callbacks — .done(), .fail(), .always(), and .then() — are invoked, in the order they are registered.