如何通过Javascript引擎在浏览器中执行Javascript?

时间:2014-02-28 20:38:29

标签: javascript javascript-engine

问题不是解决方案,更好地了解系统的问题

专家!我知道每当你将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引擎如何知道这个?

1 个答案:

答案 0 :(得分:11)

当我发布关于代码行为的答案时,我总是喜欢去两个地方:

  1. 规范
  2. 实施
  3. 规范:

    DOM API显式指定脚本必须按顺序执行:

      

    如果元素具有src属性,没有async属性,并且没有设置“force-async”标志   必须将该元素添加到脚本列表的末尾,该脚本将在准备脚本算法开始时与脚本元素的Document关联并按顺序执行

    来自4.1 Scripting。请先检查此规则的例外列表 - 拥有deferasync属性。这在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.
    

    通常最好使用模块加载器(这将推迟脚本插入和执行,并将为您正确管理依赖项)。

    目前,最好的方法是使用BrowserifyRequireJS之类的内容。将来,我们将能够使用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();
        }