Mr Cold
Mr Cold

Reputation: 1573

How to make some synchronous code run before some other asynchronous code?

I have a function like this:

var download = function(url, name) {

    http.get(url, function(response) {
        // part1 : create a new folder if it doesn't exist
        dir = './name';
        if (!fs.existsSync(dir)){
            fs.mkdirSync(dir);
        }
        // part 2: download and save file into that folder
        response.on('data', function (data) {
            fs.appendFileSync(dir, data);
        });
    })
}

I want part 1 to finish before part 2 runs (so that I can have the dir for part 2). How can I do that ?

(In the code above, as I know so far ( i am new to node.js), both parts will run simultaneously, so i'm not sure that part 1 will always finish before part 2 runs).

Upvotes: 1

Views: 1240

Answers (2)

Pascal T.
Pascal T.

Reputation: 4081

You are using sync functions, so that the calls are blocking. However, as thefoureye mentioned it is better to use the async versions, for performance reasons.

If you want to avoid the callback hell (i.e your code becomes more and more difficult to read as you chain asynchronous calls), you can use a library such as async.js that is written in the intent of trying to make it easier to write (and of course, easier to read).

Here is an example taken from the unit tests of async.js: each async function is called after the other.

var series =  function(test){
    var call_order = [];
    async.series([
        function(callback){
            setTimeout(function(){
                call_order.push(1);
                callback(null, 1);
            }, 25);
        },
        function(callback){
            setTimeout(function(){
                call_order.push(2);
                callback(null, 2);
            }, 50);
        },
        function(callback){
            setTimeout(function(){
                call_order.push(3);
                callback(null, 3,3);
            }, 15);
        }
    ],
    function(err, results){
        test.ok(err === null, err + " passed instead of 'null'");
        test.same(results, [1,2,[3,3]]);
        test.same(call_order, [1,2,3]);
        test.done();
    });
}

There are lots of other initiatives in order to make series of async calls easier to read and write (async/await, fibers.js for example)

Upvotes: 0

thefourtheye
thefourtheye

Reputation: 239653

both parts will run simultaneously

No, they will not. existsSync and mkdirSync are blocking calls. So, only after they are executed the Event handler will be attached.

But, we should take advantage of the asynchronicity whenever applicable. In this case, you can use the exists and mkdir asynchronous counterparts.

So, your code can be loosely refactored like this

function download(url, name) {

  function attachAppender(filename, response) {
    response.on('data', function (data) {
      fs.appendFile(filename, function (err) {
        res.statusCode = err ? 500 : 200;
        response.end();
      });
    });
  }

  http.get(url, function (response) {
    var dir = './name';
    fs.exists(dir, function (exists) {
      if (!exists) {
        fs.mkdir(dir, function (err) {
          if (err) {
            res.statusCode = 500;
            res.end();
          } else {
            // pass the actual full file name
            attachAppender(filename, response);
          }
        });
      } else {
        attachAppender(filename, response);
      }
    });
  });
}

Note: fs.exists is deprecated and possibly removed soon. Better use fs.stat instead of it.

Upvotes: 1

Related Questions