Rorschach
Rorschach

Reputation: 3812

Changing a Function into a synchronous execution in Javascript

I have looked through this example code:

function findItem() {
    var item;
    while(item_not_found) {
        // search
    }
    return item;
}

var item = findItem();
// do something with item
doSomethingElse();

And am trying to get my google chrome extension's code to be in the same format (synchronous).

So far I have

var token = chrome.storage.local.get('token', function (result) {
  var tokens = result.token;
  alert("IN: " + tokens);
  return tokens;
});
alert(token);

But, this doesn't work. It never prints the alert in the function at all, and the print that does appear says that token is undefined.

This asynchronous code worked:

chrome.storage.local.get('token', function (result) {
  var tokens = result.token;
});

But I need to get that value of tokens first, then move on with the other code.

Upvotes: 1

Views: 172

Answers (1)

Sukima
Sukima

Reputation: 10084

It seems there is a lack of understanding about asynchronous code. The return value really has nothing to do with your example. Based on your description of token being undefined then the .get() method ignores the return value of its callback.

In fact that is the essence of callbacks. The propose of chrome.storage.local.get() is to make the value (in this case result) available only inside the callback function not outside it. The reason for this is that the act of .get() is to do something in the background while your code continues on. It does not wait for anything and so by the time alert() is called the token variable is assigned the return value of .get() which is undefined.

There is no way to break this down without callbacks. Instead put your code inside the callback (see callback hell on why this could be a problem).

As an aside you can make this cleaner by using promises:

function promisedToken() {
  return new Promise(function(resolve, reject) {
    chrome.storage.local.get('token', resolve);
  })
  .then(function(result) {
    var tokens = result.token;
    alert("IN: " + tokens);
    return tokens;
  });
}

promisedToken()
  .then(function(token) {
    alert(token);
  });

For more on callbacks: https://github.com/maxogden/art-of-node#callbacks

Update: Based on the comment I think what your looking for is some guidance on coding style/architecture. Since this is a chrome extension we know the Promises are supported.

There is a library to provide a promise API to chrome.storage.local: https://www.npmjs.com/package/chrome-storage-promise

For clarity it can be done manually with:

In your case make a generic function that returns a promise:

function promisedGet(key) {
  return new Promise(function(resolve, reject) {
    chrome.store.local.get(key, function(result) {
      if (chrome.runtime.lastError)
        reject(chrome.runtime.lastError);
      } else {
        resolve(result);
      }
    });
  });
}

Then in your code a it is a simple matter of:

var promisedResults = promisedGet('token');
var promisedTokens = promisedResults.then(function(result) {
  return result.tokens;
});
promisedTokens.then(function(tokens) {
  alert(tokens);
  return tokens;
});

Which can easily be simplified:

promisedGet('token')
  .then(function(results) {
    alert(results.tokens);
    return results.tokens;
  });

You can make any number of chained results or functions fit for a purpose. The key difference is that any code that needs the result is executed inside a .then() function. If any of those throw an error then the error logic goes in a .catch() function. This style of programming is very expressive and composable.

Upvotes: 3

Related Questions