cujojs / when

A solid, fast Promises/A+ and when() implementation, plus other async goodies.
Other
3.44k stars 396 forks source link

settle one promise #383

Open briancavalier opened 9 years ago

briancavalier commented 9 years ago

We have when.settle(array) to settle a whole array of promises, but what about settling one promise? Is that useful? If so, then maybe we can provide Promise.prototype.settle. It'd return a promise that always fulfills (ie never rejects), with an state object (the same that when.settle uses):

when.reject('foo').then(function(state) {
    // state == { state: 'rejected', reason: 'foo' }
});
mnahkies commented 9 years ago

I think that settling an individual promise would be useful. On a similar note, I think it would be useful for all the array based functions to be available on the Promise prototype.

They could either behave the same way as spread (and not pass a value if the promise doesn't resolve to an array), or alternatively if the resolved value of the promise is not an array it could become an array of 1 element.

Examples:

Map:

when([1, 2, 3, 4])
    .then(inp => when.map(inp))
    .then(console.log); // [1, 4, 9, 16]

when([1, 2, 3, 4])
    .map(x => x * x )
    .then(console.log); // [1, 4, 9, 16]

Filter:

when([1, 2, 3, 4])
    .then(inp => when.filter(inp, x => x % 2))
    .then(console.log); // [1, 3]

when([1, 2, 3, 4])
    .filter(x => x % 2)
    .then(console.log); // [1, 3]

Combined:

whenHaveApiResult()
    .map(MyEntity.fromJSON)
    .filter(myEntity => myEntity.type === 'foobar');

It's a relatively small difference, but I think it results in more readable code.

briancavalier commented 9 years ago

Hey @mnahkies!

I think that settling an individual promise would be useful

Cool, I'd be interested in use cases you have in mind for it. Do you have any you can share?

I think it would be useful for all the array based functions to be available on the Promise prototype

Could you open a new issue to discuss this? Thanks.

mnahkies commented 9 years ago

Opened issue #468

Thinking about it further it's quite hard to come up with good use cases for settling an individual promise. Possibly something that wouldn't actually be that useful in practice.

The majority of the time the actions required for an individual promise if it resolves or rejects differ greatly, or need to be performed regardless of the outcome - .then and .ensure have these covered.

A bit of a contrived use case:

function alertSynchroniseResult(wasSuccessful){
    alert(wasSucessful ? "Synchronise Complete" : "Synchronise Failed");
}

whenSynchronised()
    .then(_.partial(alertSynchroniseResult, true), _.partial(alertSynchroniseResult, false));

whenSynchronised()
    .settle(descriptor => alertSynchroniseResult(descriptor.state === 'fulfilled'));

However, this would be better expressed by simply having the synchronise resolve to a boolean value:

whenSynchronised()
    .then(alertSynchroniseResult)

As we don't otherwise inspect the results of the settled promise, and I struggle to imagine when you would need both the value and the boolean state (and it wouldn't be better to just use then).

The main use case I have for when.settle currently is when I have a bunch of items that need processing independently, and want to wait until each has either succeeded or failed before I take any further action.