专家!我知道每当你将javascript代码提供给javascript引擎时,它会立即通过javascript引擎执行.既然,我还没有看过Engine的源代码,我的问题如下,
我们假设我从远程服务器加载了几个文件,即FILE_1.js和FILE_2.js.
并且FILE_2.js中的代码需要FILE_1.js中的一些代码.所以我已经包含如下文件,
<script type="text/javascript" src="FILE_1.js" ></script> <script type="text/javascript" src="FILE_2.js" ></script>
所以希望,我已经完成了Javascript引擎所需的工作.不幸的是,我在FILE_1.js中编写了5000KB的代码,但是我在FILE_2.js中有5KB的代码.由于服务器是多线程的,因此在FILE_1.js完成之前,FILE_2.js将被加载到我的浏览器中.
javascript引擎如何处理这个?
如果将代码从FILE_2.js移动到内联脚本标记,如下所示,javascript引擎管理此依赖项的操作是什么?
<script type="text/javascript" src="FILE_1.js" ></script> <script type="text/javascript" > // Dependent code goes here </script>
注意:我不期待单个单词回答Single Threaded.我只是想知道谁管理发布请求浏览器或javascript引擎或普通人?如果请求/响应是由普通人处理的,那么javascript引擎如何知道这一点?
解决方法
>规范
>实施
规格:
DOM API显式指定脚本必须按顺序执行:
If the element has a src attribute,does not have an async attribute,and does not have the “force-async” flag set
The element must be added to the end of the list of scripts that will execute in order as soon as possible associated with the Document of the script element at the time the prepare a script algorithm started.
从4.1 Scripting开始.请在检查此规则的例外列表之前 – 具有defer或async属性.这在4.12.1.15中有详细说明.
这是有道理的,想象一下:
//FILE_1.js var trololo = "Unicorn"; .... // 1 million lines later trololo = "unicorn"; var message = "Hello World"; //FILE_2.js alert(message); // if file 1 doesn't execute first,this throws a reference error.
通常最好使用模块加载器(这将推迟脚本插入和执行,并将正确地为您管理依赖项).
目前,最好的方法是使用像Browserify或RequireJS这样的东西.将来,我们将能够使用ECMAScript 6模块.
实施:
嗯,你提到它,我无法抗拒.所以,如果我们检查Chromium blink源代码(在WebKit中仍然类似):
bool ScriptLoader::prepareScript(const TextPosition& scriptStartPosition,LegacyTypeSupport supportLegacyTypes) { ..... } else if (client->hasSourceAttribute() && // has src attribute !client->asyncAttributeValue() &&// and no `async` or `defer` !m_forceAsync // and it was not otherwise forced ) { // - woah,this is just like the spec m_willExecuteInOrder = true; // tell it to execute in order contextDocument->scriptRunner()->queueScriptForExecution(this,m_resource,ScriptRunner::IN_ORDER_EXECUTION);
太棒了,所以我们可以在源代码中看到它按解析顺序添加它们 – 就像规范说的那样.
我们来看看script runner does:
void ScriptRunner::queueScriptForExecution(ScriptLoader* scriptLoader,ResourcePtr<ScriptResource> resource,ExecutionType executionType){ ..... // Adds it in the order of execution,as we can see,this just // adds it to a queue case IN_ORDER_EXECUTION: m_scriptsToExecuteInOrder.append(PendingScript(element,resource.get())); break; }
并且,使用计时器,它会在准备好时逐个触发它们(如果没有任何待处理的话,它会立即触发):
void ScriptRunner::timerFired(Timer<ScriptRunner>* timer) { ... scripts.swap(m_scriptsToExecuteSoon); for (size_t i = 0; i < size; ++i) { .... //fire! toScriptLoaderIfPossible(element.get())->execute(resource); m_document->decrementLoadEventDelayCount(); }