medikoo / deferred

Modular and fast Promises implementation for JavaScript
ISC License
364 stars 20 forks source link

Lot of promises remain unresolved #27

Closed bitliner closed 10 years ago

bitliner commented 10 years ago

I'm using deferred.monitor() to monitor all the promises that are still unresolved after 20 seconds the end of the program

This is the code:

deferred.monitor();
deferred.monitor(20000, function (err) {
    console.log('PROMISE',err.stack)
});

The problem is that a lot of promises remain unresolved, but they shoudn't (the line def.resolve is executed).

Someone of them rejects an error, but in this case they should be considered as resolved, shoudn't they?

May be there some causes of this behaviour?

PS: hoping this is the reight place where I can talk about this topic

medikoo commented 10 years ago

Hey @bitliner, all promises resolved with def.resolve within those 20 seconds should definitely not be reported and I'm not aware of any issue with deferred.monitor, that would do that.

Can you provide more details? Exact example (as narrowed as possible) that reproduce that would be great.

bitliner commented 10 years ago

As soon as possible i will post some of my code. Using deferred.monitor(), shoudn't even rejected promises be reported, not as unresolved ?

medikoo commented 10 years ago

@bitliner yes, even rejected promises should not be reported. It's only about those never resolved (so also never rejected), which can only be result of algorithm error.

bitliner commented 10 years ago

I created an example. The example includes 2 files: main.js and MyModule.js.

main.js is the following:

// initialize monitor
deferred.monitor();
deferred.profile();
deferred.monitor(20000, function (err) {
    console.log('PROMISE',err.stack)
});

// execution of MyModule.update that returns a promise
MyModule.update({id: 'ola'}, {saluto:'ola'}, {upsert: true}).then(function(){

    var stats = deferred.profileEnd(); // End profiling
    console.log(stats.log);

    console.log('resolved')

}, function(){
    console.log('rejected')

})

MyModule.js is the following:

// function executed by main.js
var updatePromiseNumber=0;
MyModule.prototype.update=function(query,newProperties,opts){
    var def=deferred()
        , self=this
        , opts=opts||{}
        , options={
            upsert:false,
            new:true
        }

    _und.extend(options,opts)
    self.dao.update(DATABASE_NAME, 'collection_name',query, {$set:newProperties} ,options, function (err, doc) {
        updatePromiseNumber++
        if (err) {
            console.log('DEBUG','resolving',updatePromiseNumber,'th')
            return def.reject(err)
        }
        console.log('DEBUG','resolving',updatePromiseNumber,'th')
        def.resolve(doc)
    })
    return def.promise
}

The output is the following:

Deferred usage statistics:

2 Total promises initialized
2 Initialized as Unresolved
0 Initialized as Resolved

and the 2 unresolved promises are: the first one generated in MyModule (when it executes var def=deferred()) and the second one generated when it executes MyModule.update(...)

But even if 2 promises are reported as unresolved:

Do you agree?

PS: let me know if something isn't clear and you want more details

medikoo commented 10 years ago

@bitliner you mix two different functionalities :)

  1. profile will inform about every promise created, no matter whether it was resolved or not. It's to help optimize the code so developer can track places where promises are created and maybe they shouldn't.
  2. monitor is to pickup only those unresolved, so results of algorithm error

You have absolutely correct output, there are no logs as reported by monitor functionality (all is fine), and there's correct output by profile.

"Initialized as Unresolved" means that promises were initialized as unresolved, but that doesn't mean they weren't resolved later. All promises created with deferred() and then resolved with either deferred.resolve and deferred.reject are understood as unresolved at initialization. To have promise resolved at initialization, you would have to create resolved promise right away via e.g. deferred('foo'), which will create promise that's already resolved with foo value.

To use just monitor, remove any deferred.profile and deferred.profileEnd calls, and just at beginining of your code do:

deferred.monitor(20000);

If there's no output after 20 seconds, it means all created promises were resolved.

I'm closing it for now, but please let me know if still there's some issue, or something is not clear.

anjil commented 6 years ago

I used the same code shared in the documentation and even that give 2 unresolved promises. The sample is as below:

var deferred = require('deferred');

deferred.profile();

var delay = function (fn, timeout) {
  return function () {
    var def = deferred(), self = this, args = arguments;

    setTimeout(function () {
      var value;
      try {
        value = fn.apply(self, args);
      } catch (e) {
        def.reject(e);
        return;
      }
      def.resolve(value);
    }, timeout);

    return def.promise;
  };
};

var delayedAdd = delay(function (a, b) {
  return a + b;
}, 100);

var resultPromise = delayedAdd(2, 3);

console.log(deferred.isPromise(resultPromise)); // true

resultPromise(function (value) {
  // Invoked after 100 milliseconds
  console.log(value); // 5
});

var stats = deferred.profileEnd(); // End profiling
console.log(stats.log);

Output is:

true
------------------------------------------------------------
Deferred usage statistics:

2 Total promises initialized
2 Initialized as Unresolved
0 Initialized as Resolved

Unresolved promises were initialized at:
1 at /home/node/Documents/learn/scrapping/index.js:7:15
1 at Object.<anonymous> (/home/node/Documents/learn/scrapping/index.js:32:1)
------------------------------------------------------------

5

Please let me know what's the issue.

medikoo commented 6 years ago

@anjil all is as expected, and there's no issue. See it's "Initialized as Unresolved", not "Never resolved". It's those that never resolve that signal an issue.

All promises created with deferred() and then resolved with either deferred.resolve and deferred.reject are understood as "Unresolved at initialization".

To have promise resolved at initialization, you would have to create resolved promise right away via e.g. deferred('foo'), which will create promise that's already resolved with foo value.