Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does a return statement in the try block wait for an await statement in the finally block?

Consider the following snippet:

try {
    const client = getClientThatMustBeClosed();
    const data = await shortRunningOperation(client);
    return Promise.resolve(data);
} catch (error) {
    return Promise.reject(error);
} finally {
    // any exception in the following function is caught and dealt with internally...
    await longRunningOperation(client);
    client.close();
}

Ideally I want to return data to the calling function right after shortRunningOperation() completes, without waiting for longRunningOperation() to complete. But closing the client must wait until after longRunningOperation() completes.

This jsfiddle would suggest that the return statement waits for the finally block to complete... in which case, what is the correct way to get data back to the calling function ASAP without waiting for longRunningOperation() to complete?

like image 482
drmrbrewer Avatar asked Oct 27 '22 14:10

drmrbrewer


1 Answers

Here's some simple test code that shows that the finally block does execute, even after the try block returns.

function wait (ms) {
  return new Promise(resolve => {
    setTimeout(resolve, ms);
  })
}

async function test () {
  try {
    await wait(1000);
    console.log('try block complete');
    return;
  } catch (err) {
    console.log('catch err:', err);
    return;
  } finally {
    await wait(3000);
    console.log('finally block complete');
  }
}

test();

But as the OP notes, the try block value will not be returned until the finally block is completed.

If the try return value is wanted immediately, don't use a finally block. Instead, put the long duration cleanup code in the try block, but don't use the await.

function wait (ms) {
  return new Promise(resolve => {
    setTimeout(resolve, ms);
  })
}

async function test () {
  try {
    await wait(1000);
    console.log('try complete');
    
    // put cleanup here without using await
    wait(3000).then(() => {
      console.log('cleanup complete');
    });
    
    return 'try return';
  } catch (err) {
    console.log('catch err:', err);
    return err;
  }
}

test().then(result => console.log('result:', result));

Update: You can use a finally block without blocking (delaying) the try return, but only if the finally block does not contain a return or await.

function wait(ms) {
  return new Promise((resolve) => {
    setTimeout(resolve, ms);
  });
}

async function test() {
  try {
    await wait(1000);
    console.log('try complete');
    return 'try return';
  } catch (err) {
    console.log('catch err:', err);
    return err;
  } finally {
    // cleanup without await
    wait(3000).then(() => {
      console.log('long duration cleanup complete');
    });
    // do not return here
  }
}

test().then((result) => console.log('result:', result));
like image 59
terrymorse Avatar answered Nov 15 '22 12:11

terrymorse