Monday, January 29, 2018

Javascript and callbacks and defered. How can I run a function after a google gmail API request completes?

Leave a Comment

I have built up a javascript file that starts with:

var myApp = function () {  var CLIENT_ID = 'xxxxxxx'; var DISCOVERY_DOCS = ["https://www.googleapis.com/discovery/v1/apis/gmail/v1/rest"]; var SCOPES = 'https://www.googleapis.com/auth/gmail.readonly https://www.googleapis.com/auth/analytics.readonly https://www.googleapis.com/auth/drive.readonly'; var authorizeButton = document.getElementById('authorize-button');  return { 

The functions are declared like:

    getSent: function(callback) {     var request = gapi.client.gmail.users.messages.list({       'userId': 'me',       'labelIds': 'SENT',       'maxResults': 10     });      request.execute(function(response) {       $.each(response.messages, function() {         var messageRequest = gapi.client.gmail.users.messages.get({           'userId': 'me',           'id': this.id         });           messageRequest.execute(myApp.appendMessageRow);       });     });   }, 

And then run through a single function that calls others:

myApp.init(); 

How can I defer a function to be run after my google request function getsent() has been fully completed. I have tried using callbacks to another function and it runs but it runs while the getsent() is still being executed. Can I use the jQuery method defered to run the callback when done?

I have tried: myApp.getSent(myApp.gMailSyncComplete()); // Runs early

and I tried: myApp.getSent().done(myApp.gMailSyncComplete()); // no jQuery done defined

4 Answers

Answers 1

Some important errors in your code:

  • You are creating a function getSent that accepts a callback, but you are not calling the callback at all so it won't get executed ever. You should execute the callback when everything else is done.
  • You are not waiting for all message requests to be completed. You can use a library like async which has the method map to be able to execute all requests in parallel and wait for all of them to be completed before calling the callback.

With these two things in mind, and using async, this would be an example of the resulting code:

getSent: function (callback) {   var request = gapi.client.gmail.users.messages.list({     'userId': 'me',     'labelIds': 'SENT',     'maxResults': 10   })    request.execute(function (response) {     async.map(response.messages, function (msg, cb) {         var messageRequest = gapi.client.gmail.users.messages.get({           'userId': 'me',           'id': msg.id         })          messageRequest.execute(function (result) {             myApp.appendMessageRow(result)             cb()         })     }, function (err) {       if (err) throw err       callback()     })   }) } 
  • Lastly, when invoking this function, keep in mind that the callback parameter must be a function.

To make things clear, let's translate the code you wrote, myApp.getSent(myApp.gMailSyncComplete()), into an equivalent structure:

var callback = myApp.gMailSyncComplete() myApp.getSent(callback) 

When you do this, you are not passing the function but the result of the function, because you are executing it. That's why it gets executed immediately. The correct way to do this would be the following:

var callback = myApp.gMailSyncComplete myApp.getSent(callback) 

Or, in your one-liner example, myApp.getSent(myApp.gMailSyncComplete)

Answers 2

you can use javascript promise.

    function testPromise() {       let p1 = new Promise(         // The resolver function is called with the ability to resolve or         // reject the promise        (resolve, reject) => {             /*your async function*/         }     );   // defined what to do when the promise is resolved with the then() call,     // and what to do when the promise is rejected with the catch() call     p1.then(         // Log the fulfillment value         function(val) {             log.insertAdjacentHTML('beforeend', val +                 ') Promise fulfilled (<small>Async code terminated</small>)<br/>');         })     .catch(         // Log the rejection reason        (reason) => {             console.log('Handle rejected promise ('+reason+') here.');         }); } 

Answers 3

You could use jQuery promise(), check the example below.

getSent: function() { var request = gapi.client.gmail.users.messages.list({   'userId': 'me',   'labelIds': 'SENT',   'maxResults': 10 });  request.execute(function(response) {   $.each(response.messages, function() {     var messageRequest = gapi.client.gmail.users.messages.get({       'userId': 'me',       'id': this.id     });       messageRequest.execute(myApp.appendMessageRow);   }); }); }, ... $.when( myApp.getSent() ).done(function() {     // do whatever you want in here as callback }); 

Answers 4

Inside of your getSent function create a jQuery Deferred object and return a promise. Then after request.execute has finished you can call resolve/reject. I created a small snippet to show example. Maybe you can modify to fit your needs

$(document).ready(function () {      var i =0;        function getText() {          var deferred = $.Deferred();          setTimeout(function () {              i++;              deferred.resolve("text " + i);          }, 3000);          return deferred.promise();      }      getText().then(function (value) {          console.log(value);      }).then(function () {          getText().then(function (value2) {              console.log(value2);          });      });  });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment