1

I want to reject a promise which I do not built. That is, examples I've read describe something like it:

const sample = new Promise((resolve, reject) => {
    setTimeout(() => {
        reject('fail promise');
    }, 1000);
});

That reject the sample after 1s. In my case the promise I want to reject is coming as an external api call then I can't to reject in that way.

Another approaches I've read shows how the promise can be wrapped with other that uses a setTimeout to reject the new promise. Something like this:

const timeout = new Promise(function(resolve, reject) {
    setTimeout(resolve, 1000, 'one');
});

const sample = new Promise(function(resolve, reject) {
    setTimeout(resolve, 5000, 'two');
});

return Promise.race([sample, timeout]);

That force to 'reject' sample after 1s returning the other promise. That could be used to set a timeout but in fact it does not reject sample, only returns another promise and the original continues running until it rejects or resolve itself.

I can not find how can I reject correctly a promise without a library

  • You can't reject someone else's promise. Promises are designed that way on purpose. Only the creator of the promise with access to the promise executor function can resolve or reject it. Instead, use their result (whatever it is) and then create your own outcome from that. – jfriend00 Jan 17 '20 at 19:36
  • Thank you for your answer, let me know please if found a place where it is documented. In fact, I am according with you since resolve/reject methods are only allowed during promise creation but I would know if it is documented in someplace, I was looking for that but I did not have good luck to find it. – Pavel Angel Mendoza Villafane Jan 17 '20 at 20:23
  • 1
    Well, the functions to resolve and reject and promise are passed to the promise executor and they are NOT methods on a promise. That means they are only available to the code inside the executor callback function unless that callback somehow makes them available to the outside world. I can only point you to the promise documentation that shows where the `resolve()` and `reject()` functions are passed and you will see they are ONLY available to that callback. The public methods on a promise are `.then()`, `.catch()` and `.finally()`. – jfriend00 Jan 17 '20 at 20:37
  • FYI, 99.9999% of the time the existing promise model works just fine and you can resolve or reject a promise from within the executor callback function. Very occasionally, you want to be able to control your own promise from outside that callback. This [piece of code](https://stackoverflow.com/questions/37651780/why-does-the-promise-constructor-need-an-executor/37673534#37673534) shows how you can create your own Deferred object from a regular promise which can then be resolved or rejected from outside the executor. You will generally not need this and can do this only on your own promise. – jfriend00 Jan 17 '20 at 20:42
  • 90% of the answer is in the question. 1. Make sure the 'timeout' Promise rejects; 2. Chain from the Promise returned by `Promise.race()` ie `return Promise.race([sample, timeout]).then(data => doSomethingWith(data)).catch(error => /* timeout or other error from earlier in the chain will end up here */)`. In practice `.then().catch()` may well be chained to the function call in the caller. – Roamer-1888 Jan 17 '20 at 20:47

2 Answers2

1

Why do you need to reject their promise? What you care about is getting a useful result for your code, so write code that gets you that result instead.

Wrap the API call in your own promise, with a timeout rejection on your promise, and a pass-through resolve if that API yields a result before the timeout:

const attempt = new Promise( (resolve, reject) => {
  // run the actual API _and_ your rejection timeout concurrently:
  let rejected = false;

  const id = setTimeout(() => {
    rejected = true;
    reject(new Error('timeout');
  }), 1000);

  actualApiCall(some, input, args, here)
    .then(result => {
      if (rejected) return; // <- if we rejected via timeout, we no longer care.
      clearTimeout(id);     // <- always remember to properly clean up
      resolve(result);
     })
    .catch(e => {
      if (rejected) return;
      clearTimeout(id);
      reject(e)
    });
});

attempt
  .then(result => doSomethingWith(result))
  .catch(e => console.log('rejected:', e));
Mike 'Pomax' Kamermans
  • 49,297
  • 16
  • 112
  • 153
  • Thanks for your answer. Your code allow to continue `doingSomethingWith(...)` after wait 1s. That is fine, but the promise from `actualApiCall` continues running until it resolve or reject itself. Even tough it will not does anything because `rejected=true` it could continue running for longtime. In my case, after "reject" (with your approach) I'll call again several times `actualApiCall` with another parameters and same behavior could succeed again. – Pavel Angel Mendoza Villafane Jan 17 '20 at 18:08
  • I'm using this to replay a playlist. If a video required lot of time to start then go to next one. I'm using videoJS and the problem is that `play()` method returns a promise that is resolved/rejected internally without a custom control. With your approach I can to load another video but in fact the `play()` promise continues running. During testing I saw that after lot of rejects (using a similar approach) CPU grows too – Pavel Angel Mendoza Villafane Jan 17 '20 at 18:08
  • Then this is where I say "If that's the problem, _why did not you put that in your post_ so that people can actually comment on _that_ problem"? Please update your post to mention the specific library you're trying to work with, and remember to update your tags accordingly, too. – Mike 'Pomax' Kamermans Jan 17 '20 at 18:25
  • My question is something general, I tried to give you a use case only to figure out the useful of this question. That is, the problem I described is not specific for the library I gave you as example. – Pavel Angel Mendoza Villafane Jan 17 '20 at 18:31
  • It actually is specific to that library. This is a claissical X/Y Problem. Your assumption is wrong: You want to abort a task. However this is not part of the Promise API. So your library needs to have a different way to cancel something. – Lux Jan 19 '20 at 10:46
0

I can not find how can I reject correctly a promise without a library

First of all, this doesn't seems a good approach to me, even though you can do the following,

const apiPromise = externalApi();

Now apiPromise can either be in resolved or rejected state. In both cases you can throw an error like,

const rejectedPromise = apiPromise.then(
  (fulfilledValue) => { throw "error" },
  (rejetedValue) => { throw "error" }
);
rejectedPromise.catch(err => console.log(err)); //logs "error"

Read more on Promise.then()

laxman
  • 1,781
  • 4
  • 14
  • 32