0

I'm a rookie in nodejs.And now I occured a problem about Asynchronous and Synchronous in node js.

Here is my code:

var time_begin = Date.now();
console.log("begin time:" + time_begin);

arr_a = ['a', 'b', 'a', 'b', 'a', 'b']

async function iterTrans (arr_a) {

    var txs_arr_tmp = [];
    for(let aInfo of arr_a) {
        var fs = require('fs');
        if (aInfo == "a") {
            fs.readFile("./debug.json", function (error_file, data_file) {
                if (error_file) {
                    console.log(error_file)
                } else {
                    txs_arr_tmp.push("a");
                }
            });

        } else {
            txs_arr_tmp.push("b");
        }
    }
    return txs_arr_tmp;
}

iterTrans(arr_a).then((txs_arr_tmp) => {

    var content_str = JSON.stringify(txs_arr_tmp);
    console.log(content_str);
})

I hode that the console will print:

["a","b","a","b","a","b"]

But I actually got:

["b","b","b"]

I've learned and tried some methods about Asynchronous to Synchronous, but I didn't succeed.And I must use Asynchronous method in readFile.

So how can I get ["a","b","a","b","a","b"]? Who can give me some advice?

Thanks a lot!

11
  • It looks like you're trying to get ['a', 'b', 'a', 'b', 'a', 'b'], not ["a","b","a","a","a","a"]. Can you explain why you're expecting the b to be replaced with a? Commented Apr 4, 2020 at 16:15
  • can you post a working code snippet? Commented Apr 4, 2020 at 16:20
  • 1
    The readFile in you async function is still asynchronous. Use a synchronous file read in order to make sure txs_arr_tmp is done being constructed before returning. See this post on how to read multiple files: stackoverflow.com/questions/37576685/… Commented Apr 4, 2020 at 16:23
  • @IgnacyDebicki that answer does not have a "synchronous" file read. It's still asynchronous, it's just promise-based instead of callback-based. Commented Apr 4, 2020 at 16:26
  • @PatrickRoberts I know. And that is causing the issue. The for loop cycles over the asynchronous file reads, puts in the b's into the array, and returns the array before they have a chance to complete their callback pushing the appropriate values into the army. Therefore, he needs to use synchronous file reads inside the for loop, so that the asynchronous function only returns once all the files have been read Commented Apr 4, 2020 at 16:33

2 Answers 2

1

Here's how I would approach writing the function. Since your version of Node.js doesn't have support for the fs.promises API, you can use util.promisify() to convert fs.readFile() from a callback API to a promise API, then use Array.prototype.map() to create an array of promises and await the readFile() calls in parallel with Promise.all():

const fs = require('fs');
const util = require('util');
const readFile = util.promisify(fs.readFile);

const time_begin = Date.now();
console.log("begin time:" + time_begin);

const arr_a = ['a', 'b', 'a', 'b', 'a', 'b'];

async function iterTrans (arr_a) {
  // array map allows parallel asynchronicity
  const txs_arr_tmp_promises = arr_a.map(async aInfo => {
    // use early return (to avoid nesting large blocks inside if statements)
    if (aInfo !== 'a') return 'b';

    // let await throw here if file error occurs
    const data_file = await readFile('./debug.json');
    return 'a';
  });

  return Promise.all(txs_arr_tmp_promises);
}

iterTrans(arr_a).then(txs_arr_tmp => {
  const content_str = JSON.stringify(txs_arr_tmp);
  console.log(content_str);
}).catch(error => {
  // handle errors here
  console.log(error);
});
Sign up to request clarification or add additional context in comments.

Comments

1

You cannot convert something async into sync, but you can make your rest implementation wait for the async func to complete

var time_begin = Date.now();
console.log("begin time:" + time_begin);
arr_a = ['a', 'b', 'a', 'b', 'a', 'b']

async function iterTrans(arr_a) {
  var txs_arr_tmp = [];
  for (let aInfo of arr_a) {
    const fs = require('fs').promises;
    if (aInfo == "a") {
      try {
        await fs.readFile("./debug.json")
        txs_arr_tmp.push("a");
      } catch (error) {
        console.log(error)
        var obj_addr = {
          "success": false,
          "error_no": 1,
          "error_info": "err with addrs"
        }
        return res_send.jsonp(obj_addr);
      }
    } else {
      txs_arr_tmp.push("b");
    }
  }
  return txs_arr_tmp;
}

iterTrans(arr_a).then((txs_arr_tmp) => {
  var content_str = JSON.stringify(txs_arr_tmp);
  console.log(content_str);
}) 

If fs' promisified methods are not available

var time_begin = Date.now();
console.log("begin time:" + time_begin);
arr_a = ['a', 'b', 'a', 'b', 'a', 'b']

async function iterTrans(arr_a) {
  var txs_arr_tmp = [];
  for (let aInfo of arr_a) {
    let util = require('util');
    const readFile = util.promisify(require('fs').readFile);
    if (aInfo == "a") {
      try {
        await readFile("./debug.json")
        txs_arr_tmp.push("a");
      } catch (error) {
        console.log(error)
        var obj_addr = {
          "success": false,
          "error_no": 1,
          "error_info": "err with addrs"
        }
        // return res_send.jsonp(obj_addr);
      }
    } else {
      txs_arr_tmp.push("b");
    }
  }
  return txs_arr_tmp;
}

iterTrans(arr_a).then((txs_arr_tmp) => {
  var content_str = JSON.stringify(txs_arr_tmp);
  console.log(content_str);
})

3 Comments

Thank you for your answer. But I got that error : TypeError: Cannot read property 'readFile' of undefined
@VincentWang you must be using an old version of Node.js. The fs.promises API was added in version 10
@VincentWang then you can use let util = require('util'); const readFile = util.promisify(require('fs').readFile);

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.