Anthony Chung Anthony Chung - 3 months ago 19
Javascript Question

JS - chain async methods in sequence w/o callback or modification

I'm trying to add a "default callback" to a prototype that will assign a callback function (in the form of a promise) to an async method if none is provided.

The goal is to have a class's chain of async methods run synchronously

Item.async1().async2()....asyncN()


Mind you, the async functions themselves expect a callback but they're not passed as arguments in the function call (which tells me that the class needs a default behavior when the callback lookup fails)

Spec states that I cannot directly modify the behavior or side effects of the prototype methods. I can add prototype methods. We have no visibility into how these prototype methods are implemented.

TLDR: Without modifying the prototype methods, how can you chain an N number of async methods and ensure they run sequentially?

BTW: Promisifying the prototype methods in question would be helpful if I wanted to implement the promisified versions, but it looks like we're constrained to the original function calls

Answer

If .async1() and .async2() are already provided and they require a callback and you aren't allowed to modify them, then you can't achieve Item.async1().async2()....asyncN(). The methods you're calling just aren't built to work that way and if you're not allowed to change them, there's no much you can do other than replace those methods with methods that do work the way you want.

If you can create new methods with their own names that internally use the originally methods, then that can be done. One model for how to do that is jQuery animations. They allow you do things like this:

$("#progress").slideDown(300).delay(1000).slideUp(300);

And, each of those async operations will be chained together. They do that by doing the following:

  1. Each method returns the original object so chaining will work.
  2. If an async operation is already running, then each new async method that gets called goes into a queue (on the object) along with the arguments for that method.
  3. The underlying implementation of each method can use an async operation with a traditional callback (or promise). When the operation is done, it then checks the queue to see if there are more operations to be run and if so, starts the next operation form the queue and removes it from the queue.
  4. If new async operations are called while another is running, they again just get added to the end of the queue. Each object (or whatever group of items that you want to be serialized) has its own queue.

So, if the original async methods that expect callbacks were .async1() and .async2(), you could create .async1Chain() and .async2Chain() such that you could make it work like this:

Item.async1Chain().async2Chain()....asyncNChain()

Where internally, .async1Chain() would call .async1() with a local callback and that callback would be configured to check the queue to run the next queued operation if there was one.