whatwg / loader

Loader Standard
https://whatwg.github.io/loader/
Creative Commons Zero v1.0 Universal
607 stars 45 forks source link

make it possible to manually cancel preceding pipeline stages #89

Open dherman opened 9 years ago

dherman commented 9 years ago

When .provide() gives a result for a later step than the pipeline is currently at, we fulfill the earlier promise with undefined. This seems like a good candidate for cancellation, assuming JS promise cancellation gets worked out in time for us to adopt it.

Update:

We shouldn't automatically cancel preceding stages, but we should make it possible to get access to all preceding stages so that code can manually cancel them. Today they'd have to come up with their own protocol for canceling (like .resolve(undefined) or .reject(CANCELED)) but once promises have a cancellation API we should expose that for pipeline stages.

With PR #97 we now have the ability to resolve/reject the current stage but not preceding stages. Ideally, we should expose an API that hands out all preceding stages to make it plausible more future-proof for this standard to acquire additional stages. So maybe we should only expose access to an entry's stages with something like:

// ensures we get the preceding stages before resolving
let { preceding, stage } = entry.stagesUpTo('translate');

// have to resolve this before canceling the preceding stages
stage.resolve(v);

// now we can cancel the preceding stages
preceding.forEach(stage => stage.reject(CANCELED));

But that API is super awkward. If we abandon the future-proofing constraint, we can make something less goofy, but then we ought to convince ourselves we don't need to (or can't) future-proof for additional pipeline stages.

matthewp commented 9 years ago

Shouldn't the earlier promise resolive with the result of provide()?

matthewp commented 9 years ago

Same for install.

dherman commented 9 years ago

Shouldn't the earlier promise resolive with the result of provide()?

No, because the value passed to .provide() is the result of a different step.

matthewp commented 9 years ago

I'm not sure I follow. I thought we were talking about this scenario:

var origPromise = loader.import("foo");

setTimeout(function(){
  // origPromise is on step "fetch"
  loader.provide("foo", "translate", "export var a = 1;");
});

If the original import is on step "fetch" when the provide() is called then origPromise should be resolved with the result of provide.

Do you disagree here?

dherman commented 9 years ago

Do you disagree here?

Oh, no, that's not what this issue is referring to. (Although the result of origPromise won't be the actual string "export var a = 1;" but that string will continue through the pipeline to parse, link, and instantiate the module with that source.)

This issue is referring to the promise associated with the fetch step. If we were in the middle of fetching and that promise hasn't completed, and meanwhile someone calls .provide, we're basically pre-empting the fetch. So we should really inform the fetch that it's not needed anymore.

Does that make more sense?

matthewp commented 9 years ago

That makes sense, you are pre-empting the fetch but not pre-empting the entire import() promise. The import() should be resolved with the instantiated module provided by provide().

In the old spec this did not work correct. I've mentioned this previous here: https://github.com/whatwg/loader/issues/48

This effectively make define/set (the old provide/install) of little use.

dherman commented 8 years ago

Now that we've landed PR #97 I've updated this issue description.