0

If I want to promisify all code paths in myFunction, do I need to create a deferred inside myFunction?

function myFunction(options) {
  if(!options) {
    throw 'foo'; // But I want the API for myFunction to be promise-based...
  } 

  return promiseBasedApi.doSomethingAndReturnPromise();
}
Ben Aston
  • 53,718
  • 65
  • 205
  • 331

2 Answers2

2

do I need to create a deferred inside myFunction?

(That's jQuery terminology, the general case would be "Do I need to create a promise in my function?")

Only if your function doesn't already have a promise it can return; frequently, it does, if it's waiting on any asynchronous operation (ajax, some other promise-based API, etc.) to complete.


  if(!options) {
      throw 'foo'; // But I want the API for myFunction to be promise-based...
  }

If you're asking if you need to create an reject a promise for the error that options is not provided, no, I wouldn't expect that of an API. There are two aspects to an asynchronous operation's API:

  1. Initiation

  2. Completion

In the above, failing to supply options is an error during the initiation of the request. I would expect an inline exception, not an asynchronous error callback.

Errors processing the request (HTTP failures, etc.) would be errors I'd expect via the promise's rejection mechanism.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • Actually I am using the q library, so I picked it up from there.. So if I want to completely "promisify" this function then I need to return a rejected promise in the exceptional case (`throw foo;`)? Do you know if there is a shorthand to do this in q? (Point taken re initiation and completion), but this question still stands.) – Ben Aston Aug 27 '15 at 15:24
  • @BenAston: Best to mention or tag if you're using a specific library. My view is that you don't need to return a rejected promise for the above; I would throw an exception as you're doing (see the second half of my answer, which I may have added while you were writing your comment). I'm afraid I can't help with the specifics of the Q library, but most promise libs have a means of creating a rejected promise. – T.J. Crowder Aug 27 '15 at 15:27
  • The initiation vs completion concept. Is that your own idea or from a book (if so, which one)? – Ben Aston Aug 27 '15 at 15:30
  • @BenAston: I don't think I made it up, but it's not from a book either. It's just the nature of asynchronous processing: Initiation, Processing, Completion. Only the first and last really have an API presence. :-) – T.J. Crowder Aug 27 '15 at 15:36
  • "That's jQuery terminology" - To be fair, not only jQuery. Some other libs offer deferreds. Q is one such lib. – Roamer-1888 Aug 28 '15 at 22:58
  • @Roamer-1888: Yeah -- see Ben's comment above. – T.J. Crowder Aug 29 '15 at 05:18
1

No, you do not need a deferred or the Promise constructor in your function. You do need those only for non-promise-based APIs. Even then, you should not use it globally, but a separate promise capability for each asynchronous code path.

In your case, you should just return a rejected promise instead of throwing:

function myFunction(options) {
  if (!options) {
    return Promise.reject(new FooError()); // as promised!
  } 

  return promiseBasedApi.doSomethingAndReturnPromise();
}

An alternative, if you are using Bluebird, would be to wrap your throwing-or-(promise)-returning function in Promise.method. See also Should an async API ever throw synchronously? and Should a Promise.reject message be wrapped in Error? for related discussions.

Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375