0

Many similar questions have been asked before but I am sure this is different.Please read the whole of it to understand the situation.

I know the chrome API's are asynchronous.

So, what I am doing is fetching cookies for some websites like this :

var myUrl = ["mywebsite.com","mywebsite2.com","mywebsite3.com","mywebsite4.com"]; 
    var outLine = {};
    var aE;
    for (var i = 0; i < myUrl.length ; i++) {   
        outLine[myUrl[i]] = {};
        chrome.cookies.getAll({domain: myUrl[i]}, function(cookie) {
            var templar = {};
            var str = cookie[0]['domain'];
            var domain = str.split('.');
            var length = domain.length;
            var url = domain[length-2]+"."+domain[length-1];
            var cLength = cookie.length;
            console.log(cLength);
            for(var j=0; j < cLength; j++){
                templar[j] = JSON.stringify(cookie[i]);
            }
            outLine[url]=JSON.stringify(templar);


            // This should have been outside the loop but 
            // as it is asynchronous so I put it inside so eventually it 
            // will have all the cookies as desired
            // actually this was the first problem
            aE = JSON.stringify(outLine);
        });
    }

    chrome.storage.local.get('uid', function(id){
       // Here I want to use the variable aE
       //But am unable to do so due to asynchronous
       // So, it was all good when there wasn't any loop, only one
       // chrome API , but here the next chrome API call is dependent
       // on previous' value.
    });

So , by now you would have understood what the problem would be.

The variable aE is undefined.

I want to have a simple implementation , that solves this problem correctly.

Thanks.

After suggestions from trincot I did some changes like this :

... <snip> ...
outLine[url]=JSON.stringify(templar);
            aE = JSON.stringify(outLine);
console.log("Inside Startup : iteration #"+i);
            if(i == myUrl.length){
                console.log("Complete aE :"+aE);
                sendData(aE);
            }
...<snip>...
function sendData(aE){
    console.log("Inside sendData"+aE);
...<snip>...

The output :

Inside Startup : iteration #4
Complete aE : <...aE...>
Inside sendData<....aE...>
Inside Startup : iteration #4
Complete aE : <...aE...>
Inside sendData<....aE...>
Inside Startup : iteration #4
Complete aE : <...aE...>
Inside sendData<....aE...>
Inside Startup : iteration #4
Complete aE : <...aE...>
Inside sendData<....aE...>

So this prints 4 times

Now this is the problem , it should be printing only once but it is being printed 4 times.

Solution

As suggested by trincot ( It worked thanks man ):

Just changing the var to let ( since var has the scope of the whole function , regardless of block scope but let is limited to the block scope let vs var )

for (let i = 0; i < myUrl.length ; i++) {   
        outLine[myUrl[i]] = {};
        chrome.cookies.getAll({domain: myUrl[i]}, function(cookie) {
            var templar = {};
Community
  • 1
  • 1
JeremyArcher
  • 49
  • 2
  • 6
  • chrome.* API is asynchronous and this is how async js works. Put the dependent code inside getAll callback. Or use Promise.all and Promise wrapper for getAll, and use `aE` in `.then()` – wOxxOm May 27 '17 at 15:27
  • I have read it all, and it is just one of those questions about asynchronous versus synchronous code: you cannot expect to get an asynchronous result in synchronous code. – trincot May 27 '17 at 15:35
  • @wOxxOm all code cannot be put into it as I have to save it only when all urls' cookies have been fetched. – JeremyArcher May 27 '17 at 15:37
  • @trincot I do understand that , and so how do I make sure all data has been fetched ? – JeremyArcher May 27 '17 at 15:38
  • 1
    So then use an `if` inside your call back that will have a true condition when all is done, and put all dependent code in the `if` block. For the condition you can just use a counter that is defined in the outer scope. Increment it at each callback execution, and when it is equal to myUrl.length, you know you have everything. – trincot May 27 '17 at 15:39
  • @trincot That was easy, didn't think about it . Thanks a lot :) – JeremyArcher May 27 '17 at 15:46
  • @trincot That doesn't seem to work , now it prints iteration #4 ( for the 4th iteration and doesn't print other iteration nos. ) also , it comes with partial data for other iterations and that is not what I want. Also can't I use a **setTimeout** but it also doesn't seem to work :( – JeremyArcher May 27 '17 at 15:58
  • You must be doing something wrong then. Can you update your question to show what and where you print, and explain what you mean with partial data? It is all quite vague.... I did not speak about `setTimeout`, so I am not sure why that comes up ;-) – trincot May 27 '17 at 16:06
  • @trincot Please check , I have updated the question. Thanks – JeremyArcher May 27 '17 at 16:51
  • OK, the problem is that you cannot use *i* as counter. Because that counter will have reached the end before even executing the first callback (think about that for a moment -- it is important to get that). You need a separate variable for that, which you set to 0 before the outer `for` loop, and increment *inside* the callback (this is important). And you need to check that counter, not *i*. You *could* define *i* with `let` instead of `var` and then it *might* work, but then you must assume that the callbacks are executed in order, which in general cannot always be assumed. – trincot May 27 '17 at 16:59
  • @trincot Yes , I thought about that. Order doesn't matter for me right now , I only need the whole data at last. I think this would do :) – JeremyArcher May 27 '17 at 17:08

0 Answers0