Iterable Sequences

The normal paradigm for a sequence is that each step is responsible for completing itself, which is what advances the sequence. Promises work the same way.

The unfortunate part is that sometimes you need external control over a Promise/step, which leads to awkward “capability extraction”.

Consider this Promises example:

  1. var domready = new Promise( function(resolve,reject){
  2. // don't want to put this here, because
  3. // it belongs logically in another part
  4. // of the code
  5. document.addEventListener( "DOMContentLoaded", resolve );
  6. } );
  7. // ..
  8. domready.then( function(){
  9. // DOM is ready!
  10. } );

The “capability extraction” anti-pattern with Promises looks like this:

  1. var ready;
  2. var domready = new Promise( function(resolve,reject){
  3. // extract the `resolve()` capability
  4. ready = resolve;
  5. } );
  6. // ..
  7. domready.then( function(){
  8. // DOM is ready!
  9. } );
  10. // ..
  11. document.addEventListener( "DOMContentLoaded", ready );

Note: This anti-pattern is an awkward code smell, in my opinion, but some developers like it, for reasons I can’t grasp.

asynquence offers an inverted sequence type I call “iterable sequences”, which externalizes the control capability (it’s quite useful in use cases like the domready):

  1. // note: `domready` here is an *iterator* that
  2. // controls the sequence
  3. var domready = ASQ.iterable();
  4. // ..
  5. domready.val( function(){
  6. // DOM is ready
  7. } );
  8. // ..
  9. document.addEventListener( "DOMContentLoaded", domready.next );

There’s more to iterable sequences than what we see in this scenario. We’ll come back to them in Appendix B.