【问题标题】:Script is before /body but it runs before page is loaded脚本在 /body 之前,但它在页面加载之前运行
【发布时间】:2018-08-16 06:36:34
【问题描述】:

我是 web 开发的新手,我正在尝试使用 express 的 node.js。

我的目录结构如下:

第一个应用
----node_modules
----公开
--------脚本
------------additems.js
----观看次数
--------home.ejs
----app.js

粗体是文件夹,斜体是文件。

这是文件 additem.js:

console.log("js connected");
alert("test");

这是 home.ejs 文件:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Test Node</title>
</head> 
<body>       
   <h1>Dynamic Page</h1>
   <p></p>   
   <ol id='olist'>Names List</ol>

   <script type="text/javascript" src="../public/scripts/additems.js"></script>

</body>
</html>

这是 app.js 文件:

var express = require('express');
var app = express();

console.log("Server has been started!");

//app.use(express.static(__dirname + "/public"));

app.get("/", function(req,res){
    //res.send("Home Page");
     res.render("home.ejs");

 })

页面加载前正在运行javascript的问题

我知道这一点,因为警报消息出现在其他任何内容之前。此外,我尝试使用一些 DOM 元素,但它们已作为未定义返回。

搜索网络我可以看到我的脚本位置在标签之前是正确的,并且应该最后运行。

我错过了什么?

我知道使用 onload 事件的可能性,但我想避免它,除非它是必须的,除了 我想了解为什么脚本最终没有按预期运行。

更新 - 已解决

感谢 Scott Marcus 的贡献,帮助我解决了问题。

其实有双重错误。

1- 我使用了 alert() ,这不是你提到的提示。
2- 我没有在 alert() 之后提及代码,因为我从受信任的网站复制了它,我希望问题尽可能简短。但是,代码有一个错误,导致它无法以正确的方式运行。

谢谢大家。

【问题讨论】:

    标签: javascript node.js express load order-of-execution


    【解决方案1】:

    页面加载前正在运行javascript的问题

    我知道这一点,因为警报消息出现在任何内容之前 否则。

    不能怪你得出这个结论,但事实并非如此。

    alert()'s 由操作系统与生成它们的 JavaScript 异步处理,并且通常可以比 JavaScript 执行速度更快地呈现。此外,alert() 是一个“阻塞”API 调用,它会冻结 UI,因此渲染不会与处理同步。

    使用console.log() 代替alert()。你会发现这样做表明你的代码在它应该运行的时候运行。

    这是一个 alert() 如何误导您对序列流的解释的示例。

    console.clear();
    console.log("test before alert()");
    alert("Look at the console. Notice how you don't see the log message that came before me?\nEven though the JavaScript received the instruction to write to the console, the OS can render an alert() faster than that.");

    这又是相同的概念,但这次没有将任何工作卸载到操作系统:

    console.clear();
    console.log("test before console.log()");
    console.log("Look at the console. Notice how you now do see the log message that came before me?");

    【讨论】:

    • 为什么投反对票。这是正确答案。
    • 即使没有警报,它也会在我尝试使用一些 DOM 元素后运行,但它们返回为 undefined,我在 chrome 控制台中收到此错误消息:Uncaught TypeError: Cannot read property 'appendChild' of undefined。我注释了这部分代码以消除错误来源。
    • @Shadi 然后还有其他事情发生,因为当脚本位于页面底部时(在所有 HTML 元素之后),DOM 将在遇到脚本时构建。
    • 这就是我想知道的!
    • 感谢@Scott Marcus 我发现代码中的错误,现在一切都按预期工作。
    【解决方案2】:

    将脚本放在正文末尾是一种过时的模式。您应该更喜欢使用defer 属性在head 中加载脚本(阅读更多https://mdn.io/script)。如果您不能这样做,您可以在脚本中使用负载侦听器来延迟执行,直到所有加载完成。

    window.addEventListener('load', () => {console.log('tada!')});
    

    【讨论】:

    • 你有这个完全倒退。将脚本放在body 的末尾是一种非常主流且强烈推荐的模式。注册事件处理程序会占用更多内存和 CPU 资源。
    • 恐怕“其他人都在做”不是使用次优模式的正当理由。我将听从 Google 向您解释呈现阻塞 JavaScript 的缺点developers.google.com/speed/docs/insights/BlockingJSdevelopers.google.com/web/fundamentals/performance/…
    • @ScottMarcus,你会注意到$.ready() 等同于(足够)DOMContentLoaded,根据 MDN 的定义是The DOM is loaded, parsed and ready。有趣的是,DOMContentLoaded 将在 底部的任何 scripts 运行并执行之后触发,因此根据该定义,此时 DOM 未准备好。
    • 参见this fiddle 演示&lt;/body&gt; 之前的脚本在DOMContentLoaded 之前执行
    • 正确,除非您有想要查询/操作 DOM 的脚本。在这种情况下,您需要确保 DOM 在您想要使用它时已准备就绪。
    【解决方案3】:

    浏览器解析你的 HTML 并构建 DOM 需要时间,而你的脚本一遇到它就会开始运行,所以基本上你是在设置一场比赛,希望 js 解释器输掉。不是运行异步代码的可靠方式。

    【讨论】:

    • 那么,正确的方法是什么?如果能按照我的代码说明就更好了。
    • 浏览器在完成 HTML 解析之前不会遇到脚本。没有“竞争条件”。
    • Shadi — 很确定 window.onload 或 $(document).ready() 是正确执行此操作的唯一方法。
    • Scott — 没错,它在解析之前不会运行脚本,但解析发生在创建 DOM 之前。
    猜你喜欢
    • 2017-01-13
    • 2021-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多