1

I have this code, the thing with it is, I need it to get some data from that website, the string in apiurl. This code needs to download these websites, with the certain appids found in the json. It needs to download the data on these websites and store them in a json file. For some reason this does not work.

I have this piece of code in a .js file:

var gamekeys = JSON.parse(fs.readFileSync('gamekeys.json'));
var jsonstring = JSON.stringify(gamekeys, null, 4);

UpdateGamePricelist();

function UpdateGamePricelist() {
 for(var i = 0;i<gamekeys.keys.length;i++) {
  appid = gamekeys.keys[i].appid;
  
  var apiurl = "http://store.steampowered.com/api/appdetails?appids="+appid;
  
  if (i < 95) {
   
   request(apiurl, function(err, response, body) {
    if (err) {
     console.log("Error when updating game prices: " + err+"\n");
     return;
    }
    
    var apiresponse = JSON.parse(body);
    if (body == "") {
     console.log("Could not find a pricelist m8");
     return;
    }
    
    fs.writeFile("C:/Users/ahmad/Desktop/Bots/SteamKeyProfitter/gamespricelist/"+appid+".json", body, function(err) {
     if(err) {
      console.log("Error saving data to game pricelist: " + err);
      return;
     }
     console.log("Game pricelist has been updated!");
    });
   });
  }
 }
}

And I have a json file, the json file called gamekeys.json

Here it is:

{
    "keys": [
            {
                "appid": 10,
                "price":0, 
                "listofkeys":[], 
                "game": "Counter-Strike"
            },
            {
                "appid": 20,
                "price":0, 
                "listofkeys":[], 
                "game": "Team Fortress Classic"
            },
            {
                "appid": 30,
                "price":0, 
                "listofkeys":[], 
                "game": "Day of Defeat"
            },
            {
                "appid": 40,
                "price":0, 
                "listofkeys":[], 
                "game": "Deathmatch Classic"
            },

It ofcourse keeps going (2 million lines of that)

Why does the first code not create 95 json files?

Ahmad Othman
  • 167
  • 3
  • 9

1 Answers1

2

The problems is that your appid is the same for all of the writeFile invocations.

Try changing:

appid = gamekeys.keys[i].appid;

to:

let appid = gamekeys.keys[i].appid;

You need a fresh binding for all of the callbacks or otherwise they all get the same value (from the last loop iteration). Note that var would not work here, you need let. If you use i in one of the closures then you also need to use for (let i = ...) instead of for (var i = ...)

apiurl can be declared with var because its value is passed to the request() invocation instead of being captured by a closure, but if you use let alle of the time and never use var you wouldn't have to worry about it.

If you always start every program with 'use strict'; (with quotes) and never use var (using let or const instead) then you will not have problems with the scoping that you have here, so it's a good practice to follow and enforce with linters.

This is one of the problems. There may be more but this is certainly one of them.

Update

Answering the comment by Alex "why can't he use var appid"

Run this code:

for (var i = 0; i < 4; i++) {
  let appid = 'ID' + i;
  setTimeout(function () {
    console.log(appid);
  }, 500 * i);
}

And run this program:

for (var i = 0; i < 4; i++) {
  var appid = 'ID' + i;
  setTimeout(function () {
    console.log(appid);
  }, 500 * i);
}

And compare the output.

This demonstrates the difference between let and var.

See this answer for more info about the difference between let and var:

Community
  • 1
  • 1
rsp
  • 107,747
  • 29
  • 201
  • 177
  • why can't he use `var appid` the only reason it doesn't currently work is that `appid` is hoisted to the global scope because he doesn't have a `var` declaration. I thought `let` transpiles to `var` anyway and `let` only works with `strict` mode enabled to not allow the constant to be redefined. – Halfpint Dec 25 '16 at 23:51
  • @Alex You don't use `let` but `const` if you don't want constants to be redefined. The difference between `let` and `var` is block scope vs function scope. See my updated answer for an example and see [this answer](http://stackoverflow.com/questions/31285911/why-let-and-var-bindings-behave-differently-using-settimeout-function/31286220#31286220) for more details and for explanation to what *actually* `let` got transpiled to. – rsp Dec 26 '16 at 00:19
  • that makes sense, so because there is a setTimeout in that block we use `let` to bind `i` to the context of that current iteration of the loop as after 500ms `i` is `3` because the loop has finished executing but there are 4 tasks scheduled in the event queue to be processed where `i` is `3` in that lexical scope. Gotcha, I never actually considered this before, really useful to know. cheers :) – Halfpint Dec 26 '16 at 00:38