0

I have a series of Promises that I've written inside of a class:

class Executor {

    someFunction(){
        return Promise.resolve(function(){
            console.log(this.name);
        });
    };

    someOtherFunction(){
        return Promise.resolve(function(){
            console.log(this.date);
        });
    };

    execute(){
        let {someFunction, someOtherFunction} = this;
        this.name = "John";
        this.date = "Saturday";
        someFunction=someFunction.bind(this)
        someFunction().then(someOtherFunction.bind(this));
    }

}

that I then invoke by instantiating the class and running the execute method:

var e = new Executor;
e.execute();

Is there a better way to bind the context of the class to multiple functions rather than writing multiple bind() statements?

Amit
  • 45,440
  • 9
  • 78
  • 110
fox
  • 15,428
  • 20
  • 55
  • 85
  • 1
    Context caching. `class Executor { var self = this; someFunction() { console.log(self.name); // Use self now. ...` – Tushar Nov 06 '15 at 07:03
  • you could at least write a helper function to cut down on repetition. it's good to keep functions pure via `this`, so the bind() is a good mechanism, it's just long-winded. – dandavis Nov 06 '15 at 07:03
  • 1
    you can also just use fat arrows in ES6, which does that bind stuff for you, more or less... – dandavis Nov 06 '15 at 07:05
  • 1
    why are you working so hard? `this.someFunction().then(() => this.someOtherFunction)` - simple, single line, no fuss. – Amit Nov 06 '15 at 07:07
  • (P.S. you code is very broken - `someFunction` declared twice, used as if the function is called, but really isn't...) – Amit Nov 06 '15 at 07:10
  • whoops, hopefully fixed now – fox Nov 06 '15 at 07:11
  • 2
    WTH? I'm pretty sure you did *not* mean to fulfill your promises with function objects and never call these log statements, did you? – Bergi Nov 06 '15 at 13:03
  • nope, what's the correct edit here? – fox Nov 08 '15 at 06:44
  • Are you OK with polluting Promise.prototype? –  Nov 08 '15 at 09:53

3 Answers3

1

You don't really need destructing here, it only complicates things, KISS:

'use strict';
class Executor {
  someFunction() {
    return new Promise((resolve, reject) =>  {
      setTimeout(() => {
        console.log(this.name);
        resolve();
      }, 250);
    });
  };

  someOtherFunction() {
    return new Promise((resolve, reject) =>  {
      setTimeout(() => {
        console.log(this.date);
        resolve();
      }, 250);
    });
  };

  execute() {
    this.name = "John";
    this.date = "Saturday";
    this.someFunction()
      .then(() => this.someOtherFunction())
      .then(() => { console.log('done!'); });
  }
}

let e = new Executor();
e.execute();

Note that your Promise usage was broken.

Amit
  • 45,440
  • 9
  • 78
  • 110
  • what if I want both functions to be promises? – fox Nov 06 '15 at 07:18
  • You can, but it's a dangerous anti-pattern (see link in answer). – Amit Nov 06 '15 at 07:20
  • @fox - still looking for an answer? (what's not clear?) – Amit Nov 06 '15 at 07:42
  • @Amit: No use of the promise construction antipattern. In fact he doesn't use the `Promise` constructor at all. – Bergi Nov 06 '15 at 13:04
  • @Bergi - if `someFunction` & `someOtherFunction` both return `new Promise(...)`, and `someOtherFunction` is invoked within the `then(...)` of `someFunction` - then it *is* the anti-pattern, and that's what fox asked about. – Amit Nov 06 '15 at 13:10
  • @Amit: The OP uses `Promise.resolve`, not `new Promise`. – Bergi Nov 06 '15 at 13:28
  • @Bergi I really don't understand why we're in this argument but... *what if I want both functions to be promises* is the question asked by OP regarding my answer where `new Promise` is used. – Amit Nov 06 '15 at 13:54
  • @Amit: OK, maybe I was just confused… whatever. – Bergi Nov 06 '15 at 14:14
  • so what's the correct pattern in this case if I'm not supposed to chain promises like this? – fox Nov 08 '15 at 06:43
  • @fox - every asynchronous function should return a Promise (like `someFunction` in my answer), and synchronous functions should not deal with Promises at all. Chaining is simple as in `execute`. – Amit Nov 08 '15 at 07:26
  • @Amit: so, in my OP I was looking to chain two async functions (your code here has one aysnc and one sync function). That makes me think that my error is in the way that I am invoking these with promises and not returning the promises inside of a wrapping function. What is the correct way to invoke two async promises in a chain together, one after the other? – fox Nov 08 '15 at 08:02
  • @fox - your code contains invalid use of the `Promise` constructor (see `someFunction` in this answer for proper use). Other then that, you can repeat this pattern for both functions, and in `execute` either bind or wrap with arrow function like I showed. – Amit Nov 08 '15 at 08:13
  • @Amit: can I trouble you to update your code above with two async functions? after you do that, I will accept this answer. – fox Nov 08 '15 at 09:17
  • @Amit: also, is it correct to be invoking the functions without binding the `this` context? – fox Nov 08 '15 at 09:23
  • @fox - changed code. you don't have to bind if you wrap with an arrow function - see code. – Amit Nov 08 '15 at 09:51
  • @Amit: do you need to bind `this` to `someFunction()`? – fox Nov 08 '15 at 09:53
  • @fox - I don't see why (or where to be more accurate). The call is made using `this` --> `this.someFunction()`. What would you bind? – Amit Nov 08 '15 at 10:02
  • @Amit: in my original code above, I bound `this` to `someFunction()` before invoking it. In your code, do you have access to `name` and `date` inside of `someFunction()`? – fox Nov 08 '15 at 10:05
  • @fox - you don't need to bind anything. – Amit Nov 08 '15 at 12:30
1

Is there a better way to bind the context of the class to multiple functions rather than writing multiple bind() statements?

There are difference ways of referring to the value of this, or bind a function (see How to access the correct `this` / context inside a callback?), but a shorthand to bind multiple functions at once does not exist.

Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
1

This approach may or may not thrill you. We define a context method on Promise to attach a context to the promise, and a thenWithContext method to do a then with automatic binding of the handlers passed in.

Object.defineProperties(Promise.prototype, {

  context: { value: function(context) { this.context = context; return this; } },

  thenWithContext: { value: function(resolve, reject) {
    return this.then(
      (...args) => typeof resolve === 'function' && resolve.call(this.context, ...args),
      (...args) => typeof reject  === 'function' && reject.call (this.context, ...args)
    ).context(this);
  } }

});

Usage:

execute() {
  this.someFunction() . context(this) . thenWithContext(this.someOtherFunction);
}