javascriptbrowserpromise

How to set result on a Promise outside of its constructor callback?


How do you resolve/reject a Promise outside of the constructor callback? My goal is to return a Promise that will later be resolved/rejected in the middle of a promise chain. E.g.,

function makeApiCall(form_data) {
    const out_promise = new Promise(); // Promise to return.
    // TypeError: Promise resolver undefined is not a function

    fetch(url, {body: form_data))
        .then(preprocessApiResponse)
        .then(async (response) => {
            out_promise.resolve(response); // Resolve created promise.
            //          ^ undefined
            return response;
        }, async (reason) => {
            out_promise.reject(reason); // Reject created promise.
            //          ^ undefined
            return error;
        })
        .finally(cleanupApiResponse);

    return out_promise;
}

response = await makeApiCall(form_data);


Solution

  • The direct solution is Promise.withResolvers, native implementation of a deferred pattern. In this case its use would be a special case of promise construction antipattern. If there's an existing promise, there is no need to construct a new one, with new Promise or Promise.withResolvers.

    That the snippet mixes up async..await and raw promises and tends to use an antipattern suggests that it was written in a suboptimal way. error and response are returned through the promise chain but remain unused.

    it could be refactored to async..await, which is supposed to fully replace raw promises in common cases:

    async function makeApiCall(form_data) {
      try {
        const rawResponse = await fetch(url, {body: form_data))
        const response = await preprocessApiResponse(rawResponse);
        return response; 
      } finally {
        cleanupApiResponse();
      }
    }