So time to actually start thinking about ES5, now that ES6 is out (but not everywhere, and I've no intention of babel-ing on). This means Promises and time to understand how it escapes callback hell.

My first concern was OO/encapsulation: given that Promises run in a different scope, how does an Object use them internally, because "this" means the wrong thing inside the executor function wrapped by the Promise? One answer is playing with .bind(), but the code examples for it were, in my opinion, unreadable.

So short answer is passing in the necessary context as a matter of scope variables. Either the infamous var that=this (and make sure every property you need is public in some way), or declare them piece by piece:

MyObject = {  
  _myField: "Fred",
  myMethod: function(param) {
    var myField = this._myField;
    return new Promise(function(rs, rj) {
      var x = myField; var p = param; // both of these are accessible
      // ... incl resolve, reject...
    });
  }
};

Leading to code using this class as

var o = Object.create(MyObject);  
o.myMethod('Smith').then(function(data) { }).catch(function(data) {});  

This allows you to chain methods against that object via .then.

For now I'm tending to the piece by piece, unless there are other methods to call internally.

Speaking of which, how does one deal with Promises inside Promises?

Well, once inside the Promise, things must resolve or reject. No passing around a promise to be handled elsewhere anymore, unlike the chain pattern. As such, you need to make sure that your internal chain has its main catch() method, which then rejects so that the outer Promise scope can then catch it. Failure to do so will have an internal error show up in your console (error thrown not caught) and possibly cause your outer chain to neither then nor catch, stopping execution flow.

MyObject = {  
  _myField: "Fred",
  myMethod1: function(param) {
    var myField = this._myField;
    return new Promise(function(rs, rj) {
      var x = myField; var p = param; // both of these are accessible
      // ... incl resolve, reject...
    });
  },
  myMethod2: function(param) {
    var that = this;
    return new Promise(function(rs, rj) {
      that.myMethod1(param).then(function(d) { rs(d); }).catch(function(e) { rj(e); });
    });
  }
};

So there is a short example - the outer myMethod2 returns a Promise that internally runs myMethod1, and passes its resolve via .then and reject via .catch.

Finally, one thing I found is that when writing unit tests of Promises, you sometimes want to make sure you catch the internal intentional failures, but along the way you still need to make sure your .then.catch chain continues to function...but this creates an issue as a catch later in the chain will still catch errors intentionally thrown by earlier parts. No easy solution, as such: you really need, in the later catch() methods, to check in detail what you've gotten. If it is what you expect, then return the next method in the chain to test. If it isn't, then throw it so a later (and final) catch can log that your test failed to execute.

librarian.lockFile("test1.txt").then(function(data) {  
  writeResult("SUCCESS: test1 lockFile success");
  return librarian.testLockFile("test1.txt");
}).catch(function(e) {
  // this was not expected
  writeResult("ERROR: test1 lockFile failed", e);
  throw new Error(JSON.stringify(e));
}).then(function(data) {
  writeResult("SUCCESS: test1 testLockFile success");
  return librarian.testLockFile("test1.txt", true);
}).catch(function(data) {
  // here, I want to get MY failure that the file was not locked
  // but if I catch the Error thrown above, I need to ignore it and pass it on
  if (data.constructor === Error) throw data;
  writeResult("SUCCESS: test1 testLockFile (notByMe) success");
  return librarian.unlockFile("test1.txt");
}).then(function(data) {
  writeResult("SUCCESS: test1 unlockFile success");
}).catch(function(e) {
  // here, I will finally catch that error from the first .catch block, rethrown by the second
  writeResult("FAIL: test1 lockFile fail", e);
});

So there we are.

On my old friend, Object.observe() - O.o(), soon to be going the way of Live365 it seems, an interesting alternative presented itself in mobservable. Horrible naming aside, it seems to work by taking your original object's pure properties and wrapping them in the new (ES5) setter/getter define property syntax, with the setters capable of firing change events to catch or bind to elsewhere. I may play with it some more in a future project, but I'm likely to just keep using observe-js within SubFire for now.