0

I created this couple lines of code to mess around. I have a list of movie titles from which I read in said titles with line-reader. If I console log line, I get back the original order, however, after calling the function the order becomes random. my question is why, when I return a promise and use await. Here's my code:

const axios = require("axios").default
//const db =require('./db')

const lineReader = require('line-reader');

lineReader.eachLine('./movies.txt', async function(line) {
    const movie=await getMovie(line)
    console.log(movie)
});


async function getMovie(title){
    return new Promise((resolve,reject)=>{
        axios.get("http://www.omdbapi.com/?t="+title+"&apikey=myapikey").then((result)=>{
            const data=result.data
            const movie={
                "id":data.imdbID,
                "title":data.Title,
                "year":data.Year+"-01-01",
                "runtime":data.Runtime,
                "genres":data.Genre,
                "director":data.Director,
                "plot":data.Plot,
                "rating":parseFloat(data.imdbRating)
            }
            //db.insert(movie)
            resolve(movie)
        });
    })
}

Patrick Visi
  • 100
  • 1
  • 7
  • 4
    Consider: Did each request leave your network in order? Did each request complete its transit of the internet in order? Did the destination server process your requests in order? Did each request take the same amount of time to process? Did each response transit the internet in order? As you can see you can't predetermine the final order. – Jasen Jul 07 '21 at 21:41
  • 2
    `eachLine` does not wait for the result of the callback function before reading the next line and calling it again. – Bergi Jul 08 '21 at 00:17
  • 3
    Btw, avoid the [`Promise` constructor antipattern](https://stackoverflow.com/q/23803743/1048572?What-is-the-promise-construction-antipattern-and-how-to-avoid-it)! `axios.get` already returns a promise. – Bergi Jul 08 '21 at 00:18

2 Answers2

1

Following line-reader documentation, the callback function of eachLine method supports 3 parameters, you can use cb to go to next line when getMovie done.

const axios = require("axios").default
//const db =require('./db')

const lineReader = require('line-reader');

lineReader.eachLine('./movies.txt', async function (line, last, callback) {
  const movie = await getMovie(line)
  console.log(movie);

  callback(last);
});


async function getMovie(title) {
  const { data } = await axios.get("http://www.omdbapi.com/?t=" + title + "&apikey=myapikey");

  const { imdbID, Title, Year, Runtime, Genre, Director, Plot, imdbRating } = data;
  const movie = {
    "id": imdbID,
    "title": Title,
    "year": Year + "-01-01",
    "runtime": Runtime,
    "genres": Genre,
    "director": Director,
    "plot": Plot,
    "rating": parseFloat(imdbRating),
  };
  return movie;
}
hoangdv
  • 15,138
  • 4
  • 27
  • 48
1

That's because the async functions called in eachline will return at different times. They are "fire and forget", and not synchronous.

The order won't be random. If you have a lot of lines, ones at the beginning will most certainly return before ones at the end.

Promise.all guaranties to resolve promises in the order they were called and let's you do something useful with the results.

I'm surprised that this line-reader doesn't have a map like function (and why does it have that last parameter?). But in 2021 something like this seems like an idiomatic way to preserve the order of your input lines.

let lines = []
lineReader.eachLine('./movies.txt', lines.push)

Promise.all(lines.map(getMovie)).then(console.log)
Robert Moskal
  • 21,737
  • 8
  • 62
  • 86