DaNy3LL
DaNy3LL

Reputation: 43

Wait for function to end (in async.series) doesn't work as expected

I have a nodejs script that gets some json data containing item names and prices using an API, then checks the price of that item. The problem I have is that the function that checks the item name gets executed before the function that writes the price list ends. So if the price list file doesn't exist, it gives me 'no such file or directory' for the price list file. I searched for some time on the internet, and I found something about async.series. I tried something, but it doesn't seem to work, since the result is the same. If the price list file exists, the message 'Prices updated successfully! Lenght:' appears after printing the item price.

function getPrices() {
    console.log("URL requested: ", API_URL)

    restling.get(API_URL).then(function(result) {
        var JSON_Data = result.data

        if (JSON_Data.status == "success") {
            console.log("Prices updated successfully! Lenght: "+JSON_Data.prices.length)
        } else {
            console.log(JSON_Data)
            console.log("An error ocurred during updating prices!")
            return
        }

        fs.writeFileSync("prices/pricelist.txt", JSON.stringify(JSON_Data.prices))
    })
}

function getItemPrice(item) {
    var file = JSON.parse(fs.readFileSync("prices/pricelist.txt"))

    for (var i = 0; i < file.length; i++) {
        if (file[i].item_name == item) {
            return file[i].price
        }
    }
}

function getItem() {
    var item1 = getItemPrice('Sword');
    console.log(item1);
}

async.series([
    function(callback){ 
        getPrices(); 
        callback();
    },
    function(callback){ 
        getItem();
        callback();
    }
]);

EDIT : I've tried something else, but the problem remains the same

async.series([
    function(callback){ 
        getPrices(); 
        callback();
    },
    function(callback){ 
        getItem();
        callback();
    }
], function(error){
    if (error) {
        console.log(error);
    }
});

async.waterfall([
    function(callback){ 
        getPrices(); 
        callback();
    },
    function(arg1, callback){ 
        getItem();
        callback();
    },
], function (error) {
    if (error) {
        console.log(error);
    }
});

Upvotes: 1

Views: 905

Answers (2)

Gonzalo Bahamondez
Gonzalo Bahamondez

Reputation: 1371

Mmm, i think not makes so much sense write the response in a file for read later, since you can use directly the response to find the item, but this should works.

function getPrices(callback) {

  restling.get(API_URL).then(function(result) {
    var JSON_Data = result.data

    if (JSON_Data.status == "success") {
      console.log("Prices updated successfully! Lenght: " + JSON_Data.prices.length)
    } else {
      console.log(JSON_Data)
      console.log("An error ocurred during updating prices!")
      return
    }

    fs.writeFileSync("prices/pricelist.txt", JSON.stringify(JSON_Data.prices))
    callback(null, null);
  });
}


function getItemPrice(item) {
  var file = JSON.parse(fs.readFileSync("prices/pricelist.txt"))

  for (var i = 0; i < file.length; i++) {
    if (file[i].item_name == item) {
      return file[i].price
    }
  }
}


function getItem(callback) {
  var item1 = getItemPrice('Sword');
  callback(null, item1);
}


async.series([ 
  getPrices,
  getItem
], 
function(err, result) {
  if (err) {
    console.log(err);
    return;
  }
  console.log("result", result);
});

I think a promises based approach and manipulating the response directly instead of writing / reading form a file , will be easier to understand.

function getPrices(url) {
  return new Promise( function(resolve) {
    reslint.get(url).then( function(result) {
        var data = result.data;
        if(data.status === "success") {
          console.log(
            "Prices updated successfully! Lenght: ", 
            data.prices.length
          );
          return resolve(data.prices);
        }
        else {
          throw new Error("An error ocurred during updating prices!");
        }
      })
      .catch(function(ex) {
        throw ex;
      });
  }); 
}


function getItemPrice(item, items) {
  for (var i = 0; i < items.length; i++) {
    if (items[i].item_name == item) {
      return items[i].price
    }
  }
}


getPrices("some/url/which/return/prices")
  .then(function(prices) {
    console.log(getItemPrice("Sword", prices));
  })
  .catch(function(err) {
    console.log("some error -->", err);
  });

Upvotes: 1

user5971808
user5971808

Reputation:

If I am not mistaken doesn't series expect a final callback.

async.series([
    function(callback){ 
        getPrices(); 
        callback();
    },
    function(callback){ 
        getItem();
        callback();
    }
],
function(error, [callback array]){
});

Where the callback array will contain the result returned from the functions array. Maybe try async.waterfall?

Upvotes: 0

Related Questions