Ruan Martinelli
Ruan Martinelli

Reputation: 364

Promises with ES6 destructuring?

I've tried mixing Promises with ES6 destructuring syntax (just for experimentation purposes) but the following code throws an error:

function delay(ms) {
  return new Promise((resolve, reject) => {
    setTimeout(() => resolve(), ms)
  })
}

const { then } = delay(2000)

console.log(typeof then) // ==> 'function'

// throws TypeError:
then(() => {
  console.log(`done!`)
})

On Node.js v7.10.1 it prints:

TypeError: Cannot read property 'Symbol(promise_state_symbol)' of undefined

Chrome console also throws a TypeError, but with a different message:

Uncaught TypeError: Method Promise.prototype.then called on incompatible receiver undefined

These errors don't say much to me. What's better explanation for this?

Upvotes: 0

Views: 6777

Answers (2)

Patrick J. S.
Patrick J. S.

Reputation: 2935

You are Assigning the then method to a variable, but then accesses this. You could use bind to achieve what you want.

Basically methods in javascript are just functions that are using this. If you are “stealing” the function and don't supply a this value, you are in dangerous territory.

Also the then you're extracting is most likely from Promise.prototype, not a function specific to the delay function.

You just found a fancy way to get the method from the object. It has not much to do with destucturing at all…

let p;
const {then} = p = delay(2000);
const then1 = p.then;

console.assert(then === Promise.prototype.then)
console.assert(then1 === then, 'thens aren\'t the same')

But you want a then, that somehow ensures, that you call it on the right promise.

So you could either go with

const p = delay(2000);
const then = p.then.bind(p);
…

Or construct another anonymous function

const p = delay(2000);
const then = fn => p.then(fn)

Note that this is not what you want, because it start the timeout when you are calling your then.

const then = fn => delay(2000).then(fn) // ⚠ setTimeout gets called when you are calling then.

I see no way how you would achieve what you want in one line, but maybe others have an idea.

Upvotes: 1

Bergi
Bergi

Reputation: 665286

It means that then is a method and you did not call it on any instance - you just called it as a function without any this context (or "receiver", as the second error message names it properly). You essentially did

const then = Promise.prototype.then
console.log(typeof then) // ==> 'function'
then(() => {}) // throws TypeError

You could use call

const promise = delay(2000);
then.call(promise, console.log);

or just properly invoke promise.then(console.log).

Upvotes: 3

Related Questions