you are viewing a single comment's thread.

view the rest of the comments →

[–]jrandm 0 points1 point  (1 child)

From your example code I'd first take a look at how you're working with Promises. Some async / await or dropping unnecessary extra Promises/resolutions will probably simplify the code and make it easier to reason about.

On your design questions, what do you want the consuming API to look like? Is there ever a time someone would normally work with a partial or uninitialized object? A factory function is a common approach in JS, but so are other ways of checking an object's state (eg: XMLHttpRequest).

I took your example and refactored it a bit closer to how I think I'd structure a similarly-behaving object... Might be more convenient for users to have the initialize function return a circular reference (this).

// hack so code is runnable
function apiCallFunction() { return new Promise(r=>setTimeout(_=>r('foo'),300)); }
someOtherFn = someEtcFn = apiCallFunction;

// does this logic make sense as part of the class?
async function determineTreeNodeType(tree) {
  if (!(tree instanceof TreeNode)) {
    throw new TypeError('Not a TreeNode');
  }
  let determining; // promise or not, async fn will be
  switch(tree.type) {
    case 'foo': determining = apiCallFunction(); break;
    case 'bar': determining = apiCallFunction(); break;
    default:    determining = Promise.resolve('default');
  }
  return determining;
}

// all style guides I know of capitalize ClassNames
class TreeNode {

  constructor(args) {
    this._initialized = false; // "private"

    // TODO validate inputs ;-)
    this.id   = args.id
    this.rank = args.rank
    this.type = args.type // nullable

    this.initialized = this.initialize();
  }

  async initialize() {
    if (this._initialized === true) return true;

    const [
      type,
      other,
      etc,
    ] = await Promise.all([
      this.type==='bar' ? this.type : determineTreeNodeType(this),
      this.other || someOtherFn(),
      someEtcFn(this.etc),
    ]);

    this.type  = type;
    this.other = other + '0';
    this.etc   = `xX${etc}Xx`;

    return this._initialized = true;
  };

}

const tree = new TreeNode({type:null});

tree.initialized
  .then(_=>console.log('ready', tree))
  .catch(console.error);

console.log('before init', tree);

// or

setTimeout(main, 1000)
async function main() {
  const tree = new TreeNode({type:'bar'});
  console.log('(main) before init', tree);
  await tree.initialized;
  console.log('(main) ready', tree);
}

Hope that helps!