Skip to content

ES6 native Promise from Factory Function

I’m doing a deep dive into ES6 native Promises. Along the way I came across some articles that quote Douglas Crockford design choices regarding not using things like new, Object.create, this, etc. Some people are advocating the use of Factory Functions over constructors. I have also learnt that there is a lot of heated debate regarding those choices. So to avoid having this question listed as not constructive, I’d like to ask this specific question.

How can I create a factory function for a Promise without using new?

// from [MDN Docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)

var promise1 = new Promise(function(resolve, reject) {
  setTimeout(resolve, 100, 'foo');
});

console.log(promise1);
// expected output: [object Promise]

This is also true for using things like building a new Headers() for a fetch.

At some point in the factory function, I’m going to have to write:

new Promise();

Are DC and the other authors referring to custom objects only, and not builtins? What about all the other API’s that require the use of new?

Answer

If you have a “class-like” function that requires you to call it with new keyword you could convert it to a factory function using Object.create function. Like this

function Person(name) {
  this.name = name;
}

Person.prototype.sayHi = function() {
  console.log(this.name);
}

const makePerson = (name) => {
  const person = Object.create(Person.prototype);
 
  Person.call(person, name);
  
  return person;
}

makePerson('Joe').sayHi()

But this wont work with Promise because (from spec)

Promise is not intended to be called as a function and will throw an exception when called in that manner.

const makePromise = (executor) => {
  const promise = Object.create(Promise.prototype);
  
  Promise.call(promise, executor); //this line throws
  
  return promise;
}

try {
  makePromise(resolve => setTimeout(resolve, 1000, 'Hi!')).then(console.log)
} catch(e) {
  console.error('Crashed due to ', e.message)
}

Again but there is an ultimate factory that comes with Reflect API Reflect.construct. So if you want to avoid using new at all costs you could do it like this

const makePromise = (executor) => {
  return Reflect.construct(Promise, [executor], Promise)
}

makePromise(resolve => setTimeout(resolve, 1000, 'Hi!'))
  .then(console.log);