In https://github.com/servo/servo/pull/26395/files#diff-3fe97584f564214ec8e7ebbf91747e03L253-R318,
we moved from `recursive checking` of dependency status to check only the
_current module_'s dependency status and its descendant dependency status and
also circular dependency status.
However, it will cause an issue.
For example, if the module dependency is like following
```
a -> b -> c -> d -> e
f -> g -> h -> c -> d -> e
```
In this example, if the d module is still under fetching but g is trying
to advance to finish. Then, it will cause a panic because module d is
g's grand-grand-grand-descendant which means it's still under fetching
and we can't instantiate module g.
Ideally, we should get rid of the checking in #26903 so, before #26903
fixed, we can just move back to the recursive checking way which will
ensure all descendants are not fetching.
In the previous Promise.all way, we registered a promise for every
module script which means we will need to do many complex checkings like
"is this top level?" and it will make us much more difficult to understand
how the module script algorithm works.
In the new manual checking way, we will only register promises for top
level modules to notify its owner (e.g. the script element) to finish
the load. So, we can understand it much more easily and would be more
spec-aligned.
Also, I think the `Ready` and `FetchFailed` status are quite confusing
and we actually don't need them so they're removed in this patch. Then,
we will always go to `Finished` instead.
It would basically be following steps:
+-----------------+
| Failed to fetch | ----------+
+--------------+ +----------+ / +-----------------+ |
| Fetch module | ----> | Fetching | ---+ v
+--------------+ +----------+ \ +---------+ +---------------------+
| Fetched | | Advance to Finished |
+---------+ +---------------------+
| ^
v |
+-------------------+ |
| Fetch descendants | ----- if no descendants
+-------------------+
|
V
+----------------------+
| Fetching Descendants |
+----------------------+
In `Advance to Finished`, it means that module script is about to finished so it will
1. Notify all of its `ready` and `not finished` parents to finish
2. Link (instantiate) the module
3. Resolve its promise to notify owner(s) to finish
Return the highest priority error from the descendant instead of return the very first one
The test failed because we didn't return the highest priority error (which is network error in this case).
As Manish mentioned in https://github.com/servo/servo/issues/25436#issuecomment-571065323, that's because we're using the Promise.all trick to signal loads.
If we can avoid relying on Promise.all, maybe we don't need to do a complex logic like this; instead, ideally, we should always finish the module load immediately when we hit network failure so that we don't even need to do the `max()` comparison.
---
- [x] `./mach build -d` does not report any errors
- [x] `./mach test-tidy` does not report any errors
- [x] These changes fix#25436
- [x] There are tests for these changes
<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->
<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->