nuprl / Stopify

A JS-to-JS compiler that makes it easier to build Web IDEs and compile to JS.
https://zenodo.org/records/10408254
BSD 3-Clause "New" or "Revised" License
168 stars 12 forks source link

Promises #388

Open baxtersa opened 6 years ago

baxtersa commented 6 years ago

I'm working on this in the context of distributed continuations, which is much harder, but here's a polyfill for Promise.prototype.then that works with native Promises (probably modulo some error handling).

const rts = <stopify-runtime>;
const originalThen = Promise.prototype.then;
Promise.prototype.then = function <T1, T2>(onFulfilled: (v: any) => T1 | PromiseLike<T1>,
  onRejected: (e: any) => T2 | PromiseLike<T2>): Promise<T1 | T2> {

  function wrapFulfilled(v: any) {
    return rts.runtime(() =>, (doneV) => onFulfilled(doneV.value));
  }

  function wrapRejected(e: any) {
    if (e instanceof Capture) {
      return rts.runtime(() => { throw e; },
        v => {
          if (v.type === 'normal') {
            return wrapFulfilled(v.value);
          } else {
            return onRejected(v.value);
          }
        });
    } else if (reject) {
      return onRejected(e);
    } else {
      throw e;
    }
  }

  return originalThen.call(this, wrapFulfilled, wrapRejected);
}

As I work out the rest of promises I'll try to introduce this into stopify.

jvilk commented 6 years ago

Maybe I'm missing something, but native Promise.prototype.then doesn't pass resolve and reject parameters to the callback. You only get those with the Promise constructor.

baxtersa commented 6 years ago

My variable names might be misleading here, I'll edit them. But Promise.prototype.then has the signature

(onFulfilled: (value: any) => T1 | PromiseLike<T1>, onRejected: (reason: any) => T2 | PromiseLike<T2>) => Promise<T1 | T2>

So native Promise.prototype.then gets called with two callbacks (second one optional).

baxtersa commented 6 years ago

To clarify, these are the user-provided callbacks, not the internal Promise resolve/reject functions.