H
H
HoHsi2015-12-20 20:05:34
JavaScript
HoHsi, 2015-12-20 20:05:34

How to track the progress of a Promise?

Good evening!
There is a rather long promise (20+ minutes) that I would like to keep track of. As I understand it, #progress has been cut out of A+ now. How can I track the progress of a promise, preferably in a chain?
I think passing it to #then is also not the best option.
PS Do not offer the Q library , it is slow and does not correspond to half of the standard.

Answer the question

In order to leave comments, you need to log in

1 answer(s)
Y
Yuri Puzynya, 2015-12-21
@3y3

Progress was not just removed from Promise, in most cases it is an anti-pattern.
You need to understand that Promise A + are designed to encapsulate all the logic associated with the operation inside them.
That is why I do not advise you to come up with code that requires the Promise.progress, Promise.cancel methods or the Promise.isFullfilled, Promise.isRejected properties.
Those. you can still use these properties, just not in the context of A+.
Take Q or any lightweight replacement, and implement whatever you want with defer.
An example of what you end up with might be @onqu's answer.
The code he provided is exactly what you need, but instead of having a logical unit inside each promise, you have a shared state that you can change anywhere - good luck debugging.
Cancel a promise only inside it. Report state changes only with then. If you need to track the progress of downloading something, do it through events or callbacks:

function doSomethingAsync(timeout, cb) {
  var ee = new EventEmitter();
  var state = {
    progress: 0
  };

  (function loop() {
    if (state.progress === 22) return cb(null, state);
    if (state.progress === 'canceled') return cb(new Error('Action canceled'));
    if (state.progress * 1000 > timeout) return cb(new Error('Action timed out'));

    ee.emit('progress', state);
    setTimeout(loop, 1000);
  })();

  return ee;
}


function a20SecAction(actions = {}) {
  var maxActionTime = 20000;

  return new Promise((resolve, reject) => {
    var actionWithProgress = doSomethingAsync(maxActionTime, (err, result) =>
      (err ? reject : resolve)(err || result)
    );

    actionWithProgress.on('progress', actions.progress);
  });
}

a20SecAction({
  progress: (state) => console.log('state:', state.progress)
}).then(
  (res) => console.log('state: ready'),
  (err) => console.log('state:', err)
);

So, if you have an action that must complete anyway, but you need to keep track of progress (for example, downloading a file), then do not try to solve it at the promise level (A +) it will not work for you.
In my example, there are three stages:
1) Some simple asynchronous function designed in nodejs style, i.e. it takes a set of parameters and a callback like function (err, result) {}
This is your minimal building block
2) The wrapper function is the higher level where we start working with the promise. As parameters, the function accepts handlers for additional events of our operation. In this case, the operation has one additional progress event, and two main ones - fullfilled, rejected.
3) We set handlers for all events, we process the main ones in then, additional ones through the specified parameters.
In this case, I left the ability to influence the execution process from the outside, inside the progress handler. But only to demonstrate that this is in principle possible. In practice, it's best to avoid situations where the state change of an asynchronous operation comes from outside:
a20SecAction({
  progress: (state) => {
    console.log('state:', state.progress);
    if (state.progress === 7) state.progress = 'canceled';
  }
}).then(
  (res) => console.log('state: ready'),
  (err) => console.log('state:', err)
);

And finally, if you already have an external library that gives you a normal promise for an action that can last 20 seconds, and you need to be able to watch the progress - change the library.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question