JavaScript

/*
 * asyncbuilder
 * simple semi-asynchronous list builder
 * Copyright (c) 2015-2022 Jürgen Leschner - github.com/jldec - MIT license
*/

module.exports = asyncbuilder;

function asyncbuilder(mainCallBack) {

  if (!(this instanceof asyncbuilder)) return new asyncbuilder(mainCallBack);

  // private
  var results = [];
  var pending = 0;        // number of outstanding results
  var isComplete = false; // true after complete()
  var spent = false;      // true after mainCallBack()
  var asyncErr = null;    // queued async err

  // public
  this.append = append;
  this.asyncAppend = asyncAppend;
  this.complete = complete;

  //--//--//--//--//--//--//--//--//--//

  // append result immediately (no callback required)
  function append(result) {
    if (spent) throw new Error('asyncbuilder append after mainCallBack');
    if (isComplete) {
      asyncErr = asyncErr || new Error('asyncbuilder append after complete.');
      return;
    }
    results.push(result);
  }

  // reserve a slot and return a callback(err, result) for async result
  // the callback inserts the result into the slot (or propagetes any error)
  function asyncAppend() {
    if (spent) throw new Error('asyncbuilder asyncAppend after mainCallBack');
    if (isComplete) {
      asyncErr = asyncErr || new Error('asyncbuilder asyncAppend after complete.');
      return function(){};
    }
    var slot = results.push('') - 1;
    pending++;
    return function(err, result) {
      pending--;
      asyncErr = asyncErr || err;
      results[slot] = result;
      if (isComplete && !spent && !pending) {
        spent = true;
        mainCallBack(asyncErr, results);
      }
    };
  }

  // call ab.complete() after the last append() or asyncAppend()
  function complete() {
    isComplete = true;
    if (!pending && !spent) {
      spent = true;
      process.nextTick(function() {
        mainCallBack(asyncErr, results);
      });
    }
  }

}

powered by pub-server and pub-theme-doc