Use result of asynchronous chrome.cookies.getAll

2019-07-29 06:35发布

I am running into an asynchronous JavaScript problem, having trouble saving a value received in a callback method as an object literal. I am making a Chrome Extension and using the chrome.cookies.getAll method and am able to get the cookies and read them in the callback, but I am not able to save the value to the object. I am still getting the hang of objects and asynchronous JavaScript and could really use some help.

Here's the code

var app = {
    init: function() {
        this.activeCookie = {
            'sid': null
        };
        this.setupSession();
        // shows null
        console.log('session in object : ');
        console.log(this.activeCookie['sid']);
    },

    setupSession: function() {
        var that = this;

        function setCookiesAsync(that, cookie) {
            console.log(cookie);
            for(var i=0; i<cookie.length; ++i) {
                if(cookie[i]['name'] === 'sid') {
                    that.activeCookie['sid'] = cookie[i]['value'];
                    // shows a token
                    console.log('session in callback : ');
                    console.log(that.activeCookie['sid']);
                }
            }
        }

        chrome.cookies.getAll({
            'url': ST.BaseUrl
        }, function (cookie) {
            setCookiesAsync(that, cookie);

        });
    }
};

Since the callback executes after

console.log('session in object : ');
console.log(this.activeCookie['sid']);

this.activeCookie['sid'] is null.

I am wondering how I can save the value to the object so the asynchronous method saves it to the object and the subsequent lines of code execute after setupSession() is complete.

1条回答
乱世女痞
2楼-- · 2019-07-29 07:08

While this question is on a very canonical topic, it's worded and scoped well enough that providing a specific solution as well will be helpful.

Parts of init() are executed asynchronously. What this means is that by the time init() finishes executing, not all of its code is yet run. There is no way around that - code immediately after the async part will run before it.

However, if you have some code you want to specifically execute after init (like, for instance, the rest of your code!), you can do this by passing this code as a callback and adding it to an appropriate place:

init: function(callback) {
  this.activeCookie = {
    'sid': null
  };
  this.setupSession(callback);
},

setupSession: function(callback) {
  var that = this;

  function setCookiesAsync(that, cookie) {
    for(var i=0; i<cookie.length; ++i) {
      if(cookie[i]['name'] === 'sid') {
        that.activeCookie['sid'] = cookie[i]['value'];
      }
    }
    // This is the point where all of init() has finished
    if (typeof callback === "function") { callback(); }
  }

  chrome.cookies.getAll({
    'url': ST.BaseUrl
  }, function(cookie) {
    setCookiesAsync(that, cookie);
  });
}

Then you can use the code as follows:

app.init(function() {
  /* code that should execute after init */
});

Alternatively, you can use Promises.

init: function() {
  this.activeCookie = {
    'sid': null
  };
  return this.setupSession(callback); // returns a Promise
},

setupSession: function() {
  return new Promise(function(resolve, reject) {
    var that = this;

    function setCookiesAsync(that, cookie) {
      for(var i=0; i<cookie.length; ++i) {
        if(cookie[i]['name'] === 'sid') {
          that.activeCookie['sid'] = cookie[i]['value'];
        }
      }
      // This is the point where all of init() has finished
      resolve();
    }

    chrome.cookies.getAll({
      'url': ST.BaseUrl
    }, function (cookie) {
      setCookiesAsync(that, cookie);
    });
  });
}

And the usage becomes:

app.init().then(function() {
  /* code that should execute after init */
});
查看更多
登录 后发表回答