havok2063
havok2063

Reputation: 567

switching from Jquery post requests to modern Promises

I'm working on a web application project with Flask+Python on the back-end, and Javascript on the front-end. I'd like to take advantage of some of the more modern (ES6/7) styles of things, such as Promises.

I've currently been writing all my javascript using Jquery 3+. Most of the time I'm making single Ajax requests to the server at a time. I've been specifically writing my Ajax requests using $.post and .done() and .fail(), which I know is already promise-based, or promise-like. Most of my code is in the style of

  1. do function setup stuff and checks
  2. make single ajax request
  3. on success
    • good status, run several success code bits
    • bad status, run failure code
  4. on failure - run failure code

I always seem to have to account for cases of server failures + cases of server success but it returned the wrong thing, which I usually control with a status argument. I've been looking into the straight Promise syntax with then, catch, resolve, reject, and I have some questions.

  1. Is there any advantage to me switching to this format, from what I currently have, given my simple Ajax requests?

  2. Can it be used to simplify the way I currently write my requests and handle my failure cases?

Here is a simple login example that I have, with a function that is called when a login button is clicked.

    $('#loginsubmit').on('click', this, this.login);

    // Login function
    login() {
        const form = $('#loginform').serialize();

      $.post(Flask.url_for('index_page.login'), form, 'json')
          .done((data)=>{
              if (data.result.status < 0) {
                  // bad submit
                  this.resetLogin();
              } else {
                  // good submit
                  if (data.result.message !== ''){
                      const stat = (data.result.status === 0) ? 'danger' : 'success';
                      const htmlstr = `<div class='alert alert-${stat}' role='alert'><h4>${data.result.message}</h4></div>`;
                      $('#loginmessage').html(htmlstr);
                  }
                  if (data.result.status === 1){
                      location.reload(true);
                  }

              }
          })
          .fail((data)=>{ alert('Bad login attempt'); });
    }

And a typical more complex example that I have. In this case, some interactive elements are initialized when a button is toggled on and off.

    this.togglediv.on('change', this, this.initDynamic);   

    // Initialize the Dynamic Interaction upon toggle - makes loading an AJAX request
    initDynamic(event) {

        let _this = event.data;

        if (!_this.togglediv.prop('checked')){
            // Turning Off
            _this.toggleOff();
        } else {
            // Turning On
            _this.toggleOn();

            // check for empty divs
            let specempty = _this.graphdiv.is(':empty');
            let imageempty = _this.imagediv.is(':empty');
            let mapempty = _this.mapdiv.is(':empty');

            // send the request if the dynamic divs are empty
            if (imageempty) {
                // make the form
                let keys = ['plateifu', 'toggleon'];
                let form = m.utils.buildForm(keys, _this.plateifu, _this.toggleon);
                _this.toggleload.show();

                $.post(Flask.url_for('galaxy_page.initdynamic'), form, 'json')
                    .done(function(data) {
                        let image = data.result.image;
                        let spaxel = data.result.spectra;
                        let spectitle = data.result.specmsg;
                        let maps = data.result.maps;
                        let mapmsg = data.result.mapmsg;

                        // Load the Image
                        _this.initOpenLayers(image);
                        _this.toggleload.hide();

                        // Try to load the spaxel
                        if (data.result.specstatus !== -1) {
                            _this.loadSpaxel(spaxel, spectitle);
                        } else {
                            _this.updateSpecMsg(`Error: ${spectitle}`, data.result.specstatus);
                        }

                        // Try to load the Maps
                        if (data.result.mapstatus !== -1) {
                            _this.initHeatmap(maps);
                        } else {
                            _this.updateMapMsg(`Error: ${mapmsg}`, data.result.mapstatus);
                        }

                    })
                    .fail(function(data) {
                        _this.updateSpecMsg(`Error: ${data.result.specmsg}`, data.result.specstatus);
                        _this.updateMapMsg(`Error: ${data.result.mapmsg}`, data.result.mapstatus);
                        _this.toggleload.hide();
                    });
            }
        }
    }  

I know this is already roughly using promises, but can I make improvements to my code flow by switching to the Promise then catch syntax? As you can see, I end up repeating a lot of the failure case code for real failures and successful failures. Most of my code looks like this, but I've been having a bit of trouble trying to convert these into something that's like

promise_ajax_call
  .then(do real success)
  .catch(all failure cases)

Upvotes: 1

Views: 1164

Answers (1)

jas7457
jas7457

Reputation: 1782

I always use Bluebird Promises. They have a Promise.resolve function that you can utilize with ajax. One thing to know about Promises, if you throw an error in a then, it will be caught in a chained catch. One way to clean this up a bit might be something like this (keep in mind, this is pseudo)

Promise.resolve($.ajax(...some properties..))
    .then((data)=>{
        if(data.result.status < 0){
            //throw some error
        }

        // process the data how you need it
    })
    .catch((error){
        // either the ajax failed, or you threw an error in your then. either way, it will end up in this catch
    });

Upvotes: 1

Related Questions