简体   繁体   中英

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?

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) .

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM