CasperJS posting only the last item multiple times

2019-03-05 06:13发布

问题:

CasperJS is awesome but it's not posting to my localhost what my console output is.

casper.wait(5000, function () {
    casper.wait(1000, function () {
        casper.then(function(){
            for  (var i = 0 ; i < 10; i++) {
                var description = casper.fetchText(x('//*[@id="acDataId-local'+i+'"]/a')); //*[@id="acDataId-local0"]/a
                console.log(description);
                var target_date = casper.fetchText(x('//*[@id="dtDataId-local'+i+'"]/text()[1]')); 
                console.log(target_date);
                var target_location = casper.fetchText(x('//*[@id="veDataId-local'+i+'"]')); 
                console.log(target_location);

                console.log(i, description)

                casper.then(function () {

                    casper.open('http://localhost:1337/events', {
                        method: 'post',
                            data:   {
                            'description': description,
                            'target_date':  target_date,
                            'target_location':  target_location,
                        },
                        headers: {
                           "stuff":"stuff"
                        }
                    });
                });
            }
            this.echo('POST ' + i );
        });
    });
});


casper.run();

Console.log is outputting exactly when I want but it is only posting the last item. I tried to add casper.wait in a variety of places but it didn't seem to help!

回答1:

All then* and wait* functions in CasperJS are asynchronous step functions and JavaScript has function-level scope.

This means that the for-loop is executed immediately and several then() steps are scheduled to be executed after the for-loop is completely finished. At that point the function-level variables description, target_date, etc. will all have the value of the last i and i will be 10. Here is a general JavaScript example of that: JavaScript closure inside loops – simple practical example

You can either

  • change the two calls casper.then() and casper.open() to a single call casper.thenOpen() where the loop variables are passed to the function directly:

    casper.thenOpen('http://localhost:1337/events', {
        method: 'post',
            data:   {
            'description': description,
            'target_date':  target_date,
            'target_location':  target_location,
        },
        headers: {
           "stuff":"stuff"
        }
    });
    
  • or "close" the variables for each iteration by introducing an IIFE:

    for  (var i = 0 ; i < 10; i++) {
        (function(){
            var description = casper.fetchText(x('//*[@id="acDataId-local'+i+'"]/a')); //*[@id="acDataId-local0"]/a
            console.log(description);
            var target_date = casper.fetchText(x('//*[@id="dtDataId-local'+i+'"]/text()[1]')); 
            console.log(target_date);
            var target_location = casper.fetchText(x('//*[@id="veDataId-local'+i+'"]')); 
            console.log(target_location);
    
    
            console.log(i, description)
    
    
            casper.then(function () {
    
                casper.open('http://localhost:1337/events', {
                    method: 'post',
                        data:   {
                        'description': description,
                        'target_date':  target_date,
                        'target_location':  target_location,
                    },
                    headers: {
                       "stuff":"stuff"
                    }
                });
            });
        })();
    }