Function call after all scheduled callbacks (node)

I use a stream analyzer multipart/form-datato handle file and field uploads. Whenever a new field or file is processed, an event occurs and I do some processing. After all the fields and files are parsed, an event is fired 'close'where I call the completion function for the request. Here is the setup.

parser.on('fields',function(){

    handleField(callback);

});


parser.on('close',function(){
    dismiss();
})

The problem is that processing the field may take some time, which is why the "closed" listener rejects the request before I can call back the field processing listener.

I tried to use a function setImmediatethat as described

- .

dismiss() , , process.nextTick() , , .

, , dismiss() ?

+4
2

Promises Promise.all, dismiss , Promises, - .

, , , ( ) . Promises , Promise.all , .then() on.

, callback - Node I/O (.. err), handleField - Node I/O- callback. " , , , ". , "" - , N , N - , N , dismiss(). , .

var promises = [];

parser.on('fields', function() {
  promises.push(
    new Promise(function(resolve, reject) {

      // wrap the original callback into another function.
      // this function either resolves or rejects the Promise.
      handleField(function(err) {
        // if there an error,
        // pass it to reject instead of throwing it.
        if (err) {
          reject(err);
        } else {
          // calls your callback with given args.
          // resolves Promise with return value of callback.
          resolve(callback.apply(null, arguments));
        }
      });

    })
  );
});


parser.on('close', function() {
  Promise.all(promises).then(function(values) {
    dismiss(); // All resolved.
  }, function(reason) {
    console.error(reason.stack); // First reject.
    process.exit(); // Exit on error.
  });
});

Promises, Mozilla , , .


(fn)

, , , . , .then(). , , resolve reject , .


Promise.all

Promise.all(iterable) , , Promises , .

:

Promise.all([
  new Promise((resolve, reject) => setTimeout(() => resolve('work done'), 3000)),
  new Promise((resolve, reject) => reject('coffee depleted'))
]).then(
  (v) => console.log('all work done!'),
  (r) => console.error(`Error: ${r}`)
)

, 1- , . , , Promise.all , .


Shim

Node Promises, Promises library, GitHub.

npm install promise --save

require it:

var Promise = require('promise');

ES6-promisify

promisify handleFields , - Node, err :

// npm install es6-promisify --save
var promisify = require("es6-promisify")

handleField = promisify(handleField);
promises.push(
  handleField().then(function(successArgs) {
    // success callback here
  }).catch(function(err) {
    console.error(err);
  })
);

, . Promise, Promise.denodify(fn).

+1

- , API NodeJS , promises. Promises . node -to- promises libs, promisify. ( , , .)

, , , callback- "done", , :

var calls = 0;

++calls;
parser.on('fields',function(){

    handleField(callback);
    done();
});

++calls;
parser.on('close',function(){
    done();
})

function done() {
    if (--calls == 0) {
        dismiss();
    }
}

:

// ES2015 (ES6); ES5 translation below
class Tracker {
    constructor(callback) {
        this.count = 0;
        this.callback = callback;
    }

    start() {
        ++this.count;
    }

    stop() {
        if (--this.count) {
            this.callback();
        }
    }
}

var track = new Tracker(function() {
    dismiss();
});

track.start();
parser.on('fields',function(){

    handleField(callback);
    track.stop();
});

track.start();
parser.on('close',function(){
    track.stop();
})

, , Promises .: -)


ES5 Tracker:

function Tracker(callback) {
    this.count = 0;
    this.callback = callback;
}

Tracker.prototype.start = function() {
    ++this.count;
};

Tracker.prototype.stop = function() {
    if (--this.count) {
        this.callback();
    }
};
+1

Source: https://habr.com/ru/post/1616256/


All Articles