Malintha
Malintha

Reputation: 4766

Add delay between two tasks and getting unexpected execution order

I have a loop. I am performing following tasks within the loop.

  1. Reading file
  2. Send content of files to web service and get the response.

I need to add a delay between these two tasks due to the slowness of the web service. I use a setTimeout in between these two tasks. Problem is the execution order of each task. When I log the output of each task, I can see it first prints all file content read from files then "Delayed" messages(n times) and then responses from service calls. According to the console output

[File 1 content]
[File 2 content]
[File 3 content]
Delayed
Delayed
Delayed
[Service response for File1]
[Service response for File2]
[Service response for File3]

seems like these three tasks are executed parallelly but not sequentially. My goal is to execute them sequentially.

What is the problem in my code which results above behavior

Following is my code

function myFunction() {
    console.log("Delayed");
}

filenames.forEach(function (filename) {

  fs.readFile(dir + filename, 'utf8', function(err, fileContent) {

     console.log(fileContent);

     setTimeout(myFunction, 3000);


     anotherAsyncServiceCall(fileContent, function (err, response) {
    .....
    )};

}

Upvotes: 0

Views: 52

Answers (2)

anjuc
anjuc

Reputation: 169

Make your function an asyncfunction and set await to asynchronous tasks.

function myFunction() {
  console.log("Delayed");
}

let contents = [];
let responses = [];

const fileReading = async (filename) => {
  const content = await fs.readFileSync(dir + filename, 'utf8');
  contents.push(content);
}

const getResponse = async (content) => {
  const response = await anotherAsyncServiceCall(content);
  responses.push(response);
}

filenames.forEach(async function(filename) {
  await fileReading(filename);
});


contents.forEach(async function(content) {
  await getResponse(content);
});

You can get your responses from responses array.

Upvotes: 1

vikscool
vikscool

Reputation: 1313

There are different ways by which you can achieve what you are trying to do.

Using Promise as return

fs.readfile(dir + filename, 'utf8',function(err, fileContent){
 if(err) throw err;
  return anotherAsyncServiceCall(fileContent);
}).then(function(err, response){
 if(err) throw err;
  //return the response or do any thing
}).catch(function(exception){
  console.log('exception occured',exception);
});

List all the promise and then execute them all at once using Promise.all()

//creating a global variable to contain our promises
var promiseList =[];
filenames.forEach(function (filename) {
  var fileContent=  fs.readFileSync(dir + filename, 'utf8');
  promiseList.push(anotherAsyncServiceCall(fileContent));         
});

and then use the Promise.all() to execute all the promises:

Promise.all(promiseList).then(function(err,response) {
     console.log(response);
});

using async - await

fs.readfile(dir + filename, 'utf8',async function(err, fileContent){
 if(err) throw err;
 var response =  await anotherAsyncServiceCall(fileContent);
 return response;
}).catch(function(exception){
  console.log('exception occured',exception);
});

Update the fs.readFile is not a promise but is async so it supports the callback.

Upvotes: 1

Related Questions