Issue #618 - (async) Keep track of script modes in a single mode state.

This simplifies handling of combinations of async/defer by assigning one and
only one state to scripts.
If async then always async > if defer or module then defer > otherwise blocking.
This commit is contained in:
Moonchild
2020-08-25 05:52:40 +00:00
parent 2ca1cbe2f5
commit 8b397a63af
3 changed files with 61 additions and 17 deletions
+35 -13
View File
@@ -140,6 +140,18 @@ ScriptLoadRequest::AsModuleRequest()
return static_cast<ModuleLoadRequest*>(this);
}
void
ScriptLoadRequest::SetScriptMode(bool aDeferAttr, bool aAsyncAttr)
{
if (aAsyncAttr) {
mScriptMode = ScriptMode::eAsync;
} else if (aDeferAttr || IsModuleRequest()) {
mScriptMode = ScriptMode::eDeferred;
} else {
mScriptMode = ScriptMode::eBlocking;
}
}
//////////////////////////////////////////////////////////////
// ScriptLoadRequestList
@@ -1049,18 +1061,14 @@ ScriptLoader::StartLoad(ScriptLoadRequest *aRequest, const nsAString &aType,
NS_ENSURE_SUCCESS(rv, rv);
nsIScriptElement *script = aRequest->mElement;
bool async = script ? script->GetScriptAsync() : aRequest->mPreloadAsAsync;
bool defer = script ? script->GetScriptDeferred() : aRequest->mPreloadAsDefer;
nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(channel));
if (cos) {
if (aScriptFromHead && !async && !defer) {
if (aScriptFromHead && aRequest->IsBlockingScript()) {
// synchronous head scripts block lading of most other non js/css
// content such as images
cos->AddClassFlags(nsIClassOfService::Leader);
} else if (!defer) {
} else if (!aRequest->IsDeferredScript()) {
// other scripts are neither blocked nor prioritized unless marked deferred
cos->AddClassFlags(nsIClassOfService::Unblocked);
}
@@ -1315,8 +1323,15 @@ ScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
}
}
if (!request) {
// no usable preload
if (request) {
// Use a preload request.
// It's possible these attributes changed since we started the preload, so
// update them here.
request->SetScriptMode(aElement->GetScriptDeferred(),
aElement->GetScriptAsync());
} else {
// No usable preload found.
SRIMetadata sriMetadata;
{
@@ -1340,8 +1355,10 @@ ScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
version, ourCORSMode, sriMetadata,
ourRefPolicy);
request->mIsInline = false;
request->SetScriptMode(aElement->GetScriptDeferred(),
aElement->GetScriptAsync());
// set aScriptFromHead to false so we don't treat non preloaded scripts as
// Set aScriptFromHead to false so we don't treat non-preloaded scripts as
// blockers for full page load. See bug 792438.
rv = StartLoad(request, type, false);
if (NS_FAILED(rv)) {
@@ -1359,7 +1376,7 @@ ScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
request->mJSVersion = version;
if (aElement->GetScriptAsync()) {
if (request->IsAsyncScript()) {
AddAsyncRequest(request);
if (request->IsReadyToRun()) {
// The script is available already. Run it ASAP when the event
@@ -1386,7 +1403,7 @@ ScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
}
// we now have a parser-inserted request that may or may not be still
// loading
if (aElement->GetScriptDeferred() || request->IsModuleRequest()) {
if (request->IsDeferredScript()) {
// We don't want to run this yet.
// If we come here, the script is a parser-created script and it has
// the defer attribute but not the async attribute. Since a
@@ -2605,8 +2622,7 @@ ScriptLoader::PreloadURI(nsIURI *aURI, const nsAString &aCharset,
Element::StringToCORSMode(aCrossOrigin), sriMetadata,
aReferrerPolicy);
request->mIsInline = false;
request->mPreloadAsAsync = aAsync;
request->mPreloadAsDefer = aDefer;
request->SetScriptMode(aDefer, aAsync);
nsresult rv = StartLoad(request, aType, aScriptFromHead);
if (NS_FAILED(rv)) {
@@ -2621,6 +2637,9 @@ ScriptLoader::PreloadURI(nsIURI *aURI, const nsAString &aCharset,
void
ScriptLoader::AddDeferRequest(ScriptLoadRequest* aRequest)
{
MOZ_ASSERT(aRequest->IsDeferredScript());
MOZ_ASSERT(!aRequest->mInDeferList && !aRequest->mInAsyncList);
aRequest->mInDeferList = true;
mDeferRequests.AppendElement(aRequest);
if (mDeferEnabled && aRequest == mDeferRequests.getFirst() &&
@@ -2634,6 +2653,9 @@ ScriptLoader::AddDeferRequest(ScriptLoadRequest* aRequest)
void
ScriptLoader::AddAsyncRequest(ScriptLoadRequest* aRequest)
{
MOZ_ASSERT(aRequest->IsAsyncScript());
MOZ_ASSERT(!aRequest->mInDeferList && !aRequest->mInAsyncList);
aRequest->mInAsyncList = true;
if (aRequest->IsReadyToRun()) {
mLoadedAsyncRequests.AppendElement(aRequest);