1.0.0 • Published 6 years ago

phold v1.0.0

Weekly downloads
66
License
MIT
Repository
github
Last release
6 years ago

phold

Hold promise rejection until requested

Usage

phold(promise)

Assigns an empty error handler on the promise to avoid unhandledRejection and returns a function that returns a promise which resolves with the original value or rejects with the original error.

Example

const { phold } = require('phold');

async function example() {
    
    // capture any rejections so you don't get the unhandledRejection warning/crash
    const giveItBack = phold(somethingThatCouldReject());
    
    // do more work
    await someOtherAsyncStuff();
    
    try {
        // resolve or reject with original result, if any
        await giveItBack();
    }
    catch (err) {
        // will be caught if somethingThatCouldReject() rejects
    }
}

Use case

Suppose you have an asynchronous subscription channel, where you are waiting for a single message or a single error notification to arrive (e.g. notifications about jobs in a queue). The notification is triggered by a request. This means that you need to subscribe for the message before you make the request (otherwise there is a chance you'll miss the notification if the job completes really really fast).

The subscription channel is probably an event emitter, but since we're only waiting for a single message, i.e. we have a concrete final state ("job completed" or "job failed") - a promise is a nice abstraction to use to hold the value until we need it. Your code might look something like this:

async function queueExample() {

    const myJob = await createJob();
    
    const subscription = new Promise((resolve, reject) => {
        
        jobQueue
          .on('completed', (job) => {
    
              if (job.id === myJob.id) {
                  resolve(job);
              }
          })
          .on('error', (err) => {
              
              if (err.job.id === myJob.id) {
                  reject(err);
              }
          });
    });
    
    const started = await startJob(myJob);
    
    try {
        return await subscription;
    }
    catch (err) {
        return retry(myJob)
    }
}

Note how startJob is an async function - this means we're breaking the event loop without assigning a catch() handler for the subscription promise. This means that if error event arrives before startJob completes (or if you have some other async steps before you actually need the subscription) - you will get this very nice warning in your console (node 6.6.0+):

(node:9260) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:9260) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

The scary part is the DeprecationWarning - in the future such code would crash your process - and this is absolutely not what you want, because you're perfectly able to handle the rejection (e.g. by retrying the operation).

phold fixes this by assigning a catch() handler to your promise to hold the rejection until you're ready to use it.