Home > OS >  How can I force this NodeJS function to wait until fs.writeFile has completed?
How can I force this NodeJS function to wait until fs.writeFile has completed?

Time:06-23

I am implementing https.request per these instructions (https://nodejs.org/api/https.html#httpsrequesturl-options-callback) except instead of doing a stdout, I am writing to file. I want the end to wait until the file writing process is complete. How can I do this?

 process.stdout.write(d);

is changed to

fs.writeFile(path, d, err => {
   if (err) {
     console.error(err);
   } else {
     console.log("data => " path)
   }            
})

This is the entire code

const https = require('node:https');

const options = {
  hostname: 'encrypted.google.com',
  port: 443,
  path: '/',
  method: 'GET'
};

const req = https.request(options, (res) => {
  console.log('statusCode:', res.statusCode);
  console.log('headers:', res.headers);

  res.on('data', (d) => {
    process.stdout.write(d);
  });
});

req.on('error', (e) => {
  console.error(e);
});
req.end();

UPDATE

MTN posted a solution that works, but I realized that my code is slightly more complex. I read the file in chunks and save at the end. MTN's solution finishes early. Here is the code. Can anyone help me fix it?

    const request = https.request(url, (response, error) => {
      if (error) {console.log(error)}
      let data = '';
    
      response.on('data', (chunk) => {
        data = data   chunk.toString();
      });
  
      response.on('end', () => {
        fs.writeFile(path, data, err => {
          if (err) {
            console.error(err);
          } else {
            console.log("data => " path)
          }            
        })
      })
    })
  
    request.on('error', (error) => {
      console.error(error);
    })

    request.end()
  },

CodePudding user response:

You can use fs.writeFileSync() instead. Its sync so it waits for the writing to be finished

CodePudding user response:

The immediate answer would be that whatever should happen after the file was written would have to go into the callback, after your console.log. (There is nothing in your code that looks like it's supposed to run afterwards though.)


But:

Your code would be a lot simpler if you'd...

  1. Use a library for sending HTTP requests instead of the raw https module. (For example: got, axios, node-fetch, ...) - Not only do these take care of things like reading the body for you, they also have a promise interface which allows you to do point 2.

  2. Rewrite the code to uses async/await.

Here is an example with got:

import got from 'got'
import { writeFile } from 'fs/promises'

const response = await got('https://encrypted.google.com').text()
await writeFile('test.html', response)

// Whatever should happen after the file was written would simply go here!

Note: This has to be an ES6 module because I used top-level await and import, and got doesn't even support CommonJS anymore. So either your package.json would have to have "type": "module" or the file ending would have to be mjs.

CodePudding user response:

res.on(“data”, (d) => { fs.writeFile(/* Enter params here */ })

Inside the fs.writeFile, add whatever you want to do in the last callback function.

  • Related