Search code examples
typescriptes6-promise

How to properly resolve in a chained promise inside a catch block


I am using an API which creates some assets on a server. After the creation which is a Promise I have to call process() on the asset which is another Promise API call.

I want to write a method which wraps everything together and returns the id of that asset even if the process part fails which should only log the error.

I don't know how to do that with promise changing since the catch block only contains the error and I can not resolve this.

Here is the code which I have so far;

const apicalls = async ():Promise<string> =>{

    return new Promise((resolve)=>{
        client.getEnviornment().then(environment=>{
            environment.createAsset({/* some data */}).then((asset)=>{
                resolve(asset.id); // this id I need
                return asset; // but I need also try to call process
            }).then(asset=>{
                asset.process(); // another api call which could fail
            }).catch(error=>{
                // if the error is only from process() I just want to log it.
                console.log(error);
            })
        })
    })
}

Solution

  • You can refactor your existing function using async/await and try...catch...finally.

    Note that unless you want the function to throw in the case that there's a problem before getting the asset ID (and if that's the behavior you desire, see the second example), you must use the return type of string | undefined because it's not guaranteed to get that far.

    TS Playground

    async function processAssetAndGetId (): Promise<string | undefined> {
      // because any of the steps leading up to getting the asset might fail,
      // this must be the type: string | undefined
      let id: string | undefined;
      try {
        // this could fail
        const environment = await client.getEnvironment();
        // this could fail, too
        const asset = await environment.createAsset({/* some data */});
        // set id to id of asset if we get this far
        ({id} = asset);
        // process the asset
        await asset.process();
      }
      catch (exception) {
        // if an exception is thrown at any point in the above block, log it to the console
        console.error(exception);
      }
      finally {
        return id;
      }
    }
    
    const id = await processAssetAndGetId(); // string | undefined
    

    Or, don't handle potential exceptions before getting to the asset:

    TS Playground

    async function processAssetAndGetId (): Promise<string> {
      // this could fail
      const environment = await client.getEnvironment();
      // this could fail, too
      const asset = await environment.createAsset({/* some data */});
      try {
        // process the asset
        await asset.process();
      }
      catch (exception) {
        // if an exception is thrown at any point in the above block, log it to the console
        console.error(exception);
      }
      return asset.id;
    }
    
    const id = await processAssetAndGetId(); // string