3

I'm using babel's require hook in node to leverage ES6 but I'm running into some challenges with arrow functions in bluebird promise chains.

I use .bind({}) at the top of my promise chain with an empty object to create shared state where I can store previous values until I need them further down the chain. Bluebird explains this usage as a "useful side purpose".

When I switch to arrow functions, I can no longer use shared state because arrow functions use lexical this which is undefined in babel (babel automatically runs in strict mode).

Working example: https://jsbin.com/veboco/edit?html,js,console

ES6 example (not working): https://jsbin.com/menivu/edit?html,js,console

Is there any way to take advantage of arrow functions in this situation? In my code I call these methods from within an object method - shouldn't this be defined as the object from which the method is called?

Kevin Wu
  • 8,461
  • 5
  • 28
  • 28
  • 1
    The whole point of arrow functions is that they inherit the parent `this` instead, so you're basically asking for them not to do what they were designed to do. Why not make a parent variable in the outer scope, or write your code without the shared state object instead? Plus `.bind` isn't ES6 standard so you're locking yourself into Bluebird. – loganfsmyth Aug 18 '15 at 20:59
  • Got it. I should remove .bind() from all my promise chain calls. Is there any disadvantage to using a parent variable outside the promise chain? I'm thinking I will just do something like `const state = {}` and use that to store values. – Kevin Wu Aug 18 '15 at 21:04
  • 1
    There isn't really any downside compared to what you are doing with bind, but I'll second all of Bergi's "However" section below. Having external state is something I'd consider a bad idea when working with promises. It is much better to flatten everything as in http://stackoverflow.com/questions/28250680/how-do-i-access-previous-promise-results-in-a-then-chain/28250704#28250704. – loganfsmyth Aug 18 '15 at 21:28
  • @loganfsmyth How do you feel about his example regarding generator functions in ES6? http://stackoverflow.com/a/28250697/129705 – Kevin Wu Aug 18 '15 at 21:37
  • `co` and such are great. – loganfsmyth Aug 18 '15 at 22:00

1 Answers1

5

If you don't want lexically bound this, there's no need to use arrow functions. If you want dynamically bound this, just don't use arrow functions.

Of course, you could scrap that .bind({}) as a whole and use arrow functions that are bound to the object by putting everything in an object method (or an IIFE in your example):

(function() {
  this; // the value that everything is bound to
  double(2).then(result => {
    this.double = result; // store result here
    return triple(2);
  }).then(result => {
    console.log('double:', this.double);
    console.log('triple:', result);
    console.log('sum:', this.double + result);
  }).catch(err => {
    console.log(err.message);
  });
}.call({}));

However, there are much better ways to access previous results in a promise chain than contextual state, especially if you are using ES6!

Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • I looked through each of your examples. It seems like using a parent variable outside the chain is not a good solution because it introduces mutable state. If I learn how to use generators, would that solution be relatively future proofed? At this point I think the fastest solution would be to break the chain. – Kevin Wu Aug 18 '15 at 21:35
  • Yes, generators should be relatively future-proof, though you'd actually expect to replace them with async/await eventually. (They won't suddenly stop working of course, if that's what you mean). – Bergi Aug 18 '15 at 21:48