0

My code:

class MyPromise extends Promise {
  constructor(func) {
    super(func);
  }
  SomePromiseExtensionMethod() {
    // do stuff...
  }
}

let test = async function() {
  let promise = new MyPromise(function (resolve) {
    console.log('foo');

    resolve();
  });
  
  console.log('start printing:');
  
  await promise;
};

test();

I'm leaning Promise and want to create a class which derived from Promise class.

My question: Is there a way to delay printing foo until I call await promise?

UPDATE:

I want to create this class because I want to run another methods while the object is a Promise. (Just like: mypromise.SomePromiseExtensionMethod()).

UPDATE 2: My real project:

    let Task = (function () {
        let __data = {};

        __data.Run = function (...args) {
            if (args.length) {
                let func = args[0];

                return new Task(func);
            }
        };
        
        class Task extends Promise {
            constructor(action) {
                super(action);
            }
            static set Run(value) {
                return __data.Run;
            }
            static get Run() {
                return (...args) => __data.Run.call(this, ...args);
            }
        }
        return Task;
    }());
    
    let test = async () => {
      let task = Task.Run(r => r(console.log('foo')));
      
      console.log('start printing');
      
      await task;
    };
    
    test();
  • You really don't want to be extending `Promise`. That's not the way to make use of them. – zzzzBov Aug 14 '17 at 15:30
  • 3
    *"I want to create a class which derived from Promise class.*" - hint: one never needs to do that. – Bergi Aug 14 '17 at 15:31
  • Actually even in this synchronous Promise implementation, foo is a result of your call to promise, but doesn't happen before it. However, I believe that you are talking something differently. You can put the resolve invocation in a timeout callback, e.g., setTimeout(() => resolve(), 1000); – tibetty Aug 14 '17 at 15:32
  • @Bergi I have a reason to do that and I just mention it in the update. –  Aug 14 '17 at 15:37
  • Why dont you simply call a function (that returns a promise and does some console ouput)? – Jonas Wilms Aug 14 '17 at 15:37
  • @Yeah Just curious, with what methods are you extending your promises? – Bergi Aug 14 '17 at 15:43
  • @Bergi I've another update for your question. It looks like `weird` at this time :) –  Aug 14 '17 at 15:51
  • 1
    @Yeah I'm sorry to say, but your `Task.Run` method doesn't really make much sense, and even less as a static method of a promise subclass. `const taskRun = (...args) => args.length ? new Promise(args[0]) : Promise.reject()` would probably do the same job. – Bergi Aug 14 '17 at 16:05
  • @Bergi Yes. You're right. I'm following [this answer](https://stackoverflow.com/a/18015586/7739271) to to create it. I'm sorry but I come from c# background and want to make some js syntax become friendly with c#'s. There is a js plugin, like `linqjs`, so, why not have `Task.js`? `List.js` or `dotnet.js` for future? That's my dream :) –  Aug 14 '17 at 16:13
  • @Yeah Please don't. Keep the C# where it belongs, and learn the JS idioms. `Task.Run` seems to deal with threads, which we don't have. The rule is not to do heavy CPU-bound work on the client - and if you really needed to, you'd use a web worker. – Bergi Aug 14 '17 at 16:23
  • @Bergi Uhm. It's very hard while we're working with single-thread (although there is still a way to [delay](https://stackoverflow.com/a/33292942/7739271) a thread forever). So many things need to implement but js has only 1 object `Promise` for all. Maybe it's better in ES7+, I hope. –  Aug 14 '17 at 16:30

2 Answers2

1

Is there a way to delay printing foo until I call await promise?

Yes, this is known as "lazy" promises. Notice that await is just sugar for calling the then method, so we can do this by overwriting the then method and only then run the executor callback:

class MyPromise extends Promise {
  constructor(func) {
    let run;
    super((resolve, reject) => {
      run = () => func(resolve, reject);
    });
    this.run = run;
  }
  then(onfulfilled, onrejected) {
    const run = this.run;
    if (run) {
      this.run = null;
      run();
    }
    return super.then(onfulfilled, onrejected);
  }
}

(async function test() {
  let promise = new MyPromise(function (resolve) {
    console.log('foo');
    resolve();
  });

  console.log('start printing:');

  await promise;
}());

Please use this only for the learning exercise, I wouldn't recommend to use this pattern in an actual project.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Although it works like that in my Firefox, I cannot find confirmation of "Notice that await is just sugar for calling the then method" in the es spec. Moreover, it seems to say exactly the opposite: overriding of then must not affect await operator. – Serge Seredenko Aug 14 '17 at 15:52
  • Thank you! I will remember it. –  Aug 14 '17 at 16:01
  • @SergeSeredenko Where does it say that? `await` will `resolve` the value to a promise, which follows the standard A+ procedure and calls `then`. – Bergi Aug 14 '17 at 16:03
  • Here is [how await works](https://tc39.github.io/ecmascript-asyncawait/#abstract-ops-async-function-await) and [how then works](http://www.ecma-international.org/ecma-262/6.0/index.html#sec-promise.prototype.then). They both perform `PerformPromiseThen` operation separately, so they are independent. – Serge Seredenko Aug 14 '17 at 16:10
  • 1
    @SergeSeredenko Step 3 of *AsyncFunctionAwait* is the one that will call `value.then(…)` if you trace it down. Yes, this leads to *PerformPromiseThen* being called twice. – Bergi Aug 14 '17 at 16:12
  • @SergeSeredenko, you can feed `await` any value. It will wrap it into a promise, which ultimately (for promise values) will result in `then` being called according to the resolution process of promises. – MinusFour Aug 14 '17 at 16:14
  • @Bergi I do not see anything about calling `then` method in step 3. Can you please link the end of the trace where it is written? – Serge Seredenko Aug 14 '17 at 16:20
  • 1
    @SergeSeredenko *Promise Resolve Function* Step 8 and *PromiseResolveThenableJob* will do it. In short, `await x` is equivalent to `Promise.resolve(x).then(resumeWithValue, resumeWithException)`. – Bergi Aug 14 '17 at 16:26
-1

You can do that with then:

class MyPromise extends Promise {
  constructor(func) {
    super(func);
  }
}

let test = async () => {
  let promise = new MyPromise(function (resolve) {
    resolve();
  }).then(_ => console.log('foo'));
  
  console.log('start printing:');
  
  await promise;
};

test();

NB: It is a bad idea to extend the Promise object.

trincot
  • 317,000
  • 35
  • 244
  • 286
  • Sorry, I'm not the downvoter but can you explain me why it's a bad idea? Also, I have an update in the question. You can check again. Thank you! –  Aug 14 '17 at 15:38
  • 2
    This delays the printing only for some fixed time, not until `await promise`. – Bergi Aug 14 '17 at 15:41
  • It delays until after await is encountered. The await itself is resumed like before. But I understood the question to be to have the 'foo' printed later, which is achieved here. – trincot Aug 14 '17 at 16:45