Method wrappers in Async Await - Part III
In the previous post we used memoize to prevent the parallel calls to a function. In this post we will be extending the memoize implementation to handle more of the situations that may arise with asynchronous functions and extending memoize to handle those additional cases.
Here is the memoize function from lodash.
Adding State #
Note that we are attaching the state to the original promise object and not returning a new promise object. This makes it unnecessary to have the rejection re-thrown or the resolution returned. This method should be called before line 9, in case the return value is a promise. We are not checking that the function called is async and therefore would not want to crash the function by adding a
.then to a non-promise.
Generic rejection method #
The second extension we would like to do to the memoize method is to have a rejection method on the return value. We could do it via adding code to memoize like I mentioned in my byteconf talk, it is easier to add a selection method so as to make it generic. After adding the rejection method this is what memoize looks like:
Memoize takes an optional parameter
rejector which can reject a cached value. This way we could reject certain cached data based on conditions.
Here is a sample rejector:
This way of the original server request fails, we do not cache and continue using the failure results.
The save problem #
One very common problem in programming is the save problem. Say you have some document being edited and you want to trigger a save on it. If a save is in progress, you should not start saving in parallel but should wait for the save to complete. Saving should happen if the save is not in progress.
Extending memoize to perform this task is relatively simple. Here is the rejection method to implement the solution to the save problem.
In this case only if the promise is pending execution, save will not be executed. Otherwise save will go through. You might want to extend it further to delay the save call (something similar to debounce in concept). Here if the save is in progress, you want to call save again after the save is complete but if it is not running, you can call it right now.
The above rejector also has a side-effect of delaying the save call to be applied if the save is in progress.
In these posts, we saw how powerful it can be to share functionality across
async methods via creating wrappers that can solve many of our day to day problems in a generic way that could be abstracted out into a library.