Refactoring Promise Patterns

I'm sure you have written a lot of code that looks something like this:

1 2 3 4 this .get( ' model ' ); 5 this .set( ' isLoading ' , true ); 6 return band.save() 7 8 this .set( ' successMessage ' , ' Band has been saved. ' ); 9 10 catch (() => { 11 this .set( ' error ' , ' Band is too unruly to be saved. ' ); 12 13 finally (() => { 14 this .set( ' isLoading ' , false ); 15 16 17

Setting back isLoading to false is conveniently placed in a finally handler so that it happens both if the promise resolves successfully (the band is saved) and if it is rejected (there is an error during the save).

The isLoading is then used in the corresponding template to show a spinner and/or disable the save button while the save is in flight:

1 2 <button type = " button " onclick = ( action " save " ) disabled = {{ isLoading }} > Save band </button>

I know I have written this hundreds of times by now and it has increasingly disturbed me that setting and unsetting the loading flag is boilerplate code, something that could be refactored.

One nice thing about promises is that they are easy to compose. Here is how we could define a function that adds the boilerplatey parts:

You might go a tiny step further and use a default value for the loading flag:

1 2 3 function saveWithLoadingFlag (operation, loadingProperty= ' isLoading ' ) { 4 this .set(loadingProperty, true ); 5 return operation. finally (() => { 6 this .set(loadingProperty, false ); 7 8 9 10 11 12 this .get( ' model ' ); 13 return saveWithLoadingFlag.call( this , band.save()) 14 15 this .set( ' successMessage ' , ' Band has been saved. ' ); 16 17 catch (() => { 18 this .set( ' error ' , ' Band is too unruly to be saved. ' ); 19 20 21

Since saveWithLoadingFlag returns a promise, we can add our own handlers to it, including other finally handlers.

You can find a working example here, where you can play around with it.