For loops run synchronously and cannot be used to repeat asynchronous functions. Loops can only be run on data available, for example in memory.

Therefore, to master asynchronous programming we must program without loops.

Array.prototype.forEach() method

forEach accepts a closure, and invokes that closure for every item in the array.  Returns undefined.

array.forEach( (item, index, array ) => {  
  // work with item
});

Array.prototype.map() method

The map() method creates a new array with the results of calling a provided function on every element in this array.  Returns the new array. Apply transformations to every item and collect up resultant array.

var newArray = array.map( (item, index, array ) => {  
  // work with item
});

Array.prototype.filter() method

The filter() method creates a new array with all elements that pass the test implemented by the provided function.

Predicate function (closure function) returns true to keep item or otherwise false.

var newArray = array.filter ( ( item,  index,  array) => {  
  // return true or false
});

Chaining forEach, map and filter

Can chain forEach, map and filter to work over arrays.

var stocks = [  
  { symbol: "XFX", price: 240.22, volume: 23432 },  
  { symbol: "TNZ", price: 332.19, volume: 234 },  
  { symbol: "JXJ", price: 120.22, volume: 5323 },  
];

var filteredStockSymbols = stocks  
    .filter(function(stock) {
      return stock.price <= 150.00;
    })
    .map(function(stock) {
      return stock.symbol;
    });

filteredStockSymbols.forEach(function(symbol) {  
  console.log(symbol);
});

Creating a concatAll method on the array prototype

Common to work with nested data structures such as arrays of arrays.

Can be helpful to flatten nested data structures.  One approach is to nest forEach.  Call forEach on outermost array, then forEach on inner array.

Array.prototype.concatAll = function() {  
  var results = [];

  this.forEach(function(subArray) {
    subArray.forEach(function(item) {
      results.push(item);    
    });
  });

  return results;

};

The Observable with Reactive Extensions - can be implemented with ES2015 iterators

Events, asynchronous requests and animations can all be modeled as asynchronous collections that arrive over time.

Once modelled as such, can use the array methods to combine together asynchronous data sources and build complex asynchronous programs easily.

Observable Type can be used to model these as collections.

Reactive Extensions (rx.js) library provides this.

An Observable is like an array, except an array stores all data in memory whereas an Observable does not and items arrive over time.  Calling any of the array methods on an existing Observable returns an Observable, rather than an array.

Observable gives an object by which to represent event stream.  forEach on the Observable accepts three callbacks.

var Observable = Rx.Observable;  
var button = document.getElementById('button');

/*
var handler = function(e) {  
    alert('clicked');
    button.removeEventListener('click', handler);
};

button.addEventListener('click', handler);  
*/

var clicks = Observable.fromEvent(button, 'click');  
var subscription = clicks.forEach(  
        function onNext(e) {
            alert('clicked');
            subscription.dispose();
        },
        function onError(error) {
            console.log('ERROR!');
        },
        function onCompleted() {
            console.log("done");
        });