0

I'm using casperJS to loop through an array. It works fine, except when I fire an event there appears to be some sort of race condition going on.

The script navigates to a URL, waits for a selector, and then fires an event when the selector is available in the DOM. The event listener for said event then does what it does.

But the problem is, within the for loop I am getting different results for the variable ad_id. I have commented the code.

When I first grab the ad_id, it's different in each iteration (normal behavior). But calling it in the waitForSelector results in the same ad_id each time.

casper.then(function() {

    log(username, 'Grabbing demographic text and submitting to server'); 

    for(i=0; i < ads.length; i++)
    {
        ad = ads[i];
        ad_id = ad.ad_id; // Here ad_id is different each iteration
        dText = null;
        url = 'https://example.com/page.php?ad_id=' + ad_id + '&page_type=20'; 

        casper.thenOpen(url, function() {
            casper.page.injectJs(fs.workingDirectory + '/js/jquery-2.1.4.min.js');
        });

        casper.waitForSelector('#static_templates', function() {
            dText = casper.evaluate(function() {
                return $('section').first().text();
            });

            log(ad_id); // Here, all ad_id's are the same every iteration

            this.emit('demographic.recieved', ad_id, dText);
        });

        casper.wait(5000);
    }    
});

Any ideas?

BugHunterUK
  • 8,346
  • 16
  • 65
  • 121
  • `waitForSelector` is asynchronous and the callback is executed after the loop is fully executed, but the last reference to `ad_id` won't change anymore. You should "close" the `ad_id` variable for example with an [IIFE](http://stackoverflow.com/a/19324832/1816580). – Artjom B. Dec 29 '15 at 14:20
  • @ArtjomB. thank you :) Also, you should write a book, or release a course. I see you around a lot providing a lot of help. You seem knowledgeable :) – BugHunterUK Dec 29 '15 at 15:18
  • 1
    I could probably generate a book from all the answers I provided here on Stack Overflow. ;) Btw, you should see a link above your question to accept the duplicate. – Artjom B. Dec 29 '15 at 15:23
  • @ArtjomB.It works, but the problem is dText isn't set. If I place casper.emit within the waitForSelector it never fires. If I place it outside (underneath it) it works but there's no dText. – BugHunterUK Dec 29 '15 at 15:59
  • Use `this.emit('demographic.recieved', [ad_id, dText]);` or `this.emit('demographic.recieved', {ad_id:ad_id, dText:dText});`, because only one value can be emitted – Artjom B. Dec 29 '15 at 16:05
  • That works, but still `ad_id` is blank from within the `waitForSelector`. If I dump it outside of it, its visible. It's as if it's not in scope. Edit: Well the ad is there, but it's getting the same one each time. – BugHunterUK Dec 29 '15 at 16:27
  • As I said, you should use an IIFE: `(function(ad_id){ casper.waitForSelector(...); })(ad_id)` – Artjom B. Dec 29 '15 at 16:31
  • @ArtjomB. ok done all works. Do you have a beer/coffee fund? I would like to buy you one :D – BugHunterUK Dec 29 '15 at 16:44

0 Answers0