Access resolve function outside of a JavaScript Promise
If I understand your question correctly, your question runs on these assumptions:


You want to hook up multiple listeners to a single Promise.
The promise is triggered arbitrarily, not necessarily on promise creation.
You want to use native promises.
You run on an engine that has Promises.


The second bullet point, where the operation is triggered arbitrarily, is the tricky part because native promises are read-only. You'll need to catch resolve and reject from the constructor every time.

So while your implementation is correct, you'll find yourself repeating the pattern. jQuery Deferreds are better in this case, but we don't want to lug around jQuery, or any library for that matter.

What you could do is create your own little Deferred constructor. It just wraps around the existing native Promise API, essentially just forwarding arguments. The only difference is that it's exposing resolve and reject.

function Deferred(callback){
  var instance = this;

  // Catch the resolve and reject
  this._resolver = null;
  this._rejector = null;
  this._promise = new Promise(function(resolve, reject){
    instance._resolver = resolve;
    instance._rejector = reject;
  });

  // Deferred has { resolve, reject }. But personally, I like the Promise
  // version of resolve and reject as separate args.
  if(typeof callback === 'function')
    callback.call(this, this._resolver, this._rejector);
}

Deferred.prototype.then = function(resolve, reject){
  return this._promise.then(resolve, reject);
};

// resolve, reject etc.

// For other APIs, refer to jQuery for Deferred and MDN for Promises:
// https://api.jquery.com/category/deferred-object/
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise


Now with Deferred out of the way, let's go back to your jQuery version and improve it. Since we created Deferred as a constructor, we can subclass from it. This means we can have Foo become a Deferred and have the luxury of the Deferred API.

// Setup Foo as a Deferred in as little as 2 lines.
function Foo(){ Deferred.apply(this, arguments); }
Foo.prototype = Object.create(Deferred.prototype);

// Your Foo API
Foo.prototype.init = function(){
  var instance = this;
  setTimeout(function(){
    instance.resolve();
  }, 2000);
};


In the end, foo will have Deferred powers, care of an extended Promise API.

var foo = new Foo();

// We can now use `then`.
foo.then(function(){
  alert('foo.ready!');
});

//
foo.init();


Now if I wrote the code properly, this should work:



function Deferred(callback) {
  var instance = this;
  this._resolver = null;
  this._rejector = null;
  this._promise = new Promise(function(resolve, reject) {
    instance._resolver = resolve;
    instance._rejector = reject;
  });
  if (typeof callback === 'function')
    callback.call(this, this._resolver, this._rejector);
}

Deferred.prototype.then = function(resolve, reject) { return this._promise.then(resolve, reject); };
Deferred.prototype.resolve = function(resolution) { this._resolver.call(null, resolution); return this; };
Deferred.prototype.reject = function(rejection) { this._rejector.call(null, rejection); return this; };

// The setup code:

function Foo() { Deferred.apply(this, arguments); }
Foo.prototype = Object.create(Deferred.prototype);

Foo.prototype.init = function() {
  var instance = this;
  setTimeout(function() {
    instance.resolve('YAY!');
  }, 2000);
};

// Phew! Now your Foo is a "native" Deferred.

var foo = new Foo();

foo.then(function(value) {
  alert('foo.ready! ' + value);
});

foo.init();