窥探 Script 标签(步入现代 Web 开发的魔法世界)

窥探 Script 标签

0x01 什么是 script 标签?

script 标签允许你包含一些动态脚本或数据块到文档中,script 标签是非闭合的,你也可以将动态脚本或数据块当做 script 的文本节点。就是内联脚本。

一般我们最常用的就是写一些 JavaScript 脚本在 script 标签里,但是 script 也可以用来存储一些数据,比如当你设置 type="text/react" 的 script 时就可以在里面放 react 代码,但是游览器是不会执行它无法识别的 type 的,因此 script 还可以用来存放一些临时 APP 数据。

<script src="game-engine.js"></script>
<script type="text/x-game-map">
........U.........e
o............A....e
.....A.....AAA....e
.A..AAA...AAAAA...e
</script>

也可以通过 documents.scripts[0].text 获取到第一个脚本的内容,可以修改它,但是不会有任何作用。

0x02 src 属性

当你指定了 src 属性时,外部脚本的内容是不受脚本内容限制的;同时你的 script 标签内必须是空的。如果没有指定 src,就称这段脚本是内联的,内联脚本受到脚本内容限制。

什么是脚本内容限制?

<script>
    alert(‘hello <script‘) // 报错, DOM 解析器会认为 <script 是一个 script 标签开头
    alert(‘hello <!--‘)    // 报错,DOM 解析器会认为 <!-- 是一个注释开头

    if (1<script) { }      // 报错,DOM 解析器会认为 <script 是一个 script 标签开头
      if (x<!--y ) { }       // 报错,DOM 节气息会认为 <!-- 是一个注释开头

      alert(‘hello <\script‘) // 正常,添加了转义
    alert(‘hello <\!--‘)    // 正常,添加了转义
</script>

所以看得出来,如果你使用打包工具,为了减少 CRP 而将脚本内联到文档里,代码要注意是否符合脚本内容限制;如果你还压缩了代码,更需要注意这一点。

0x03 defer 和 async 属性

<script defer=defer src="xxx"></script> <!-- 这段脚本不会阻塞 DOM 解析,会并发的下载脚本,并在 DOM 解析完成之后才会执行 -->
<script async src="xxx"></script> <!-- 这段脚本不会阻塞 DOM 解析,会并发的下载脚本,并在脚本下载完成后暂停 DOM 解析,然后执行脚本 -->

0x04 type=module和 nomodule 属性

在 script 中,默认的 type="text/javascript",还可以是 JavaScript MIME 中的任意一种。如果 script 里写的是 JavaScript,推荐省略 type 属性。不指定 defer 和 async 下的经典脚本的执行会阻塞 DOM 解析。

如果 type=module,则说明标签引用的是一个 ES 模块。

<script type="module">
  import {addTextToBody} from ‘./utils.js‘;

  addTextToBody(‘Modules are pretty cool.‘);
</script>

?

// utils.js
export function addTextToBody(text) {
  const div = document.createElement(‘div‘);
  div.textContent = text;
  document.body.appendChild(div);
}

仅仅支持“裸导入”

// Supported:
import {foo} from ‘https://jakearchibald.com/utils/bar.js‘;
import {foo} from ‘/utils/bar.js‘;
import {foo} from ‘./bar.js‘;
import {foo} from ‘../bar.js‘;

// Not supported:
import {foo} from ‘bar.js‘;
import {foo} from ‘utils/bar.js‘;

支持 type=module 的游览器会自动忽略带有 nomodule 的 script 标签。方便你回退到不支持 module 的老式的用户代理。

<script type="module" src="module.js"></script>
<script nomodule src="fallback.js"></script>

而且 type=module 默认带有 defer

<!-- This script will execute after… -->
<script type="module" src="1.js"></script>

<!-- …this script… -->
<script src="2.js"></script>

<!-- …but before this script. -->
<script defer src="3.js"></script>

执行的顺序是 2.js,1.js,3.js

即便是内联的 module,依然具有 defer 属性。

<!-- This script will execute after… -->
<script type="module">
  addTextToBody("Inline module executed");
</script>

<!-- …this script… -->
<script src="1.js"></script>

<!-- …and this script… -->
<script defer>
  addTextToBody("Inline script executed");
</script>

<!-- …but before this script. -->
<script defer src="2.js"></script>

模块脚本只会执行一次

<!-- 1.js only executes once -->
<script type="module" src="1.js"></script>
<script type="module" src="1.js"></script>
<script type="module">
  import "./1.js";
</script>

<!-- Whereas normal scripts execute multiple times -->
<script src="2.js"></script>
<script src="2.js"></script>

必须符合同源策略

<!-- This will not execute, as it fails a CORS check -->
<script type="module" src="https://….now.sh/no-cors"></script>

<!-- This will not execute, as one of its imports fails a CORS check -->
<script type="module">
  import ‘https://….now.sh/no-cors‘;

  addTextToBody("This will not execute.");
</script>

<!-- This will execute as it passes CORS checks -->
<script type="module" src="https://….now.sh/cors"></script>

模块脚本在跨域的时候默认是不带 credentials 的。

<!-- Fetched with credentials (cookies etc) -->
<script src="1.js"></script>

<!-- Fetched without credentials -->
<script type="module" src="1.js"></script>

<!-- Fetched with credentials -->
<script type="module" crossorigin src="1.js?"></script>

<!-- Fetched without credentials -->
<script type="module" crossorigin src="https://other-origin/1.js"></script>

<!-- Fetched with credentials-->
<script type="module" crossorigin="use-credentials" src="https://other-origin/1.js?"></script>

下图可以很好的诠释经典脚本和模块脚本加载的不同

模块脚本的依赖层级的增加会不会导致 CRP 长度的增加?

上图可以看出,层级很深的时候,用户代理会花费大量的时间在等待依赖文件的传输和解析上,因此这会导致 CRP 长度的增加;不过 http2 push 的魔法使得用户代理下载依赖文件的时间会大幅减少,服务器会分析模块的依赖树,然后在一次请求里回传所有依赖文件给用户代理。具体的讨论可以看 Are ES6 modules in brwosers going to get loaded level-by-level 详细讨论了这个问题。

0x05 charset 属性

给出脚本内容的编码方式;没有 src 的 script 不能设置该属性,模块脚本强行按 utf8 来解析。

0x06 noscript 标签

noscript 标签告诉游览器,如果你不支持脚本或脚本被禁用,那就显示我里面的内容。通常被用作脚本被禁用的回退方案。

0x07 最后

script 标签真的令人感到兴奋。

如果你觉得我的文章不错,可以关注我的

0x08 参考文章

原文地址:https://www.cnblogs.com/homehtml/p/12219040.html

时间: 2024-10-13 11:15:21

窥探 Script 标签(步入现代 Web 开发的魔法世界)的相关文章

Django web开发【5】 实现标签功能

标签tag在很多web2.0应用中都很常见,标签其实就是关联某些信息的一个关键字.打标签实际上就是给内容分配标签的过程,它通常由作者或者用户实现.标签之所有这么流行是因为它允许用户对自己创建的博客.图像.链接等等进行分类. 既然我们要创建的是社交型网络收藏夹,标签自然非常重要,为了引进标签,我们需要一个机制来允许用户在提交bookmarks的时候带上标签一起存进数据库,并且可以浏览某个标签下的所有bookmarks. Tag 数据模型 标签需要保存在数据库中,并且与bookmarks相关联,所以

web开发中比较常用的html标签

作为一名web开发人员,总结了一下经常用到的html标签,如下:<html> <head> <!--meta头标签 表示页面三秒后跳转到新浪页面--> <meta charset="utf-8" http-equiv="refresh" content="3;url=http://www.sina.com"/> <title></title> </head> &l

WEB开发的jsp例子标签库(jstl)的使用

<!-- e1 --> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ page import=&quo

web基础----&gt;script标签的特殊使用

今天周末,首先祝大家过得开心.好了,今天要讲的就是怎样使用<script>去请求一个servlet,加载一些js资源以及额外的逻辑处理: 目录: JS的引入的几种方式 在script的标签中引入Servlet 动态引入JS的好处 友情链接 JS的引入方式 首先我们说一下,一般js引入到jsp或者html的几种方式: 直接document.write 但这样会把当前的页面全覆写掉 document.write("<script src='test.js'><\/scr

【web开发学习笔记】Struts-Tags学习笔记1 - 通用标签和控制标签

通用标签和控制标签 第一部分:代码 //前端 <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=GB18030" /> <title>Insert title here</title> </head> <body> 访问属性 <a href="<%=contextP

web开发学习笔记(3):HTML表格制作——table标签以及th、td、tr标签的使用例子

//纯属新手学习笔记,仅供参考. 代码: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http

零基础入门学习Web开发(HTML5&amp;CSS3)007&lt;noscript&gt;&lt;script&gt;

0.<script> HTML <script> 标签 定义和用法 <script> 标签用于定义客户端脚本,比如 JavaScript. script 元素既可以包含脚本语句,也可以通过 src 属性指向外部脚本文件. 必需的 type 属性规定脚本的 MIME 类型. JavaScript 的常见应用时图像操作.表单验证以及动态内容更新. 如果<script> 既有src引用内容,也有内嵌内容,最终显示的是src引用内容,内嵌内容被忽略. index.h

移动端WEB开发,click,touch,tap事件浅析

一.click 和 tap 比较 两者都会在点击时触发,但是在手机WEB端,click会有 200~300 ms,所以请用tap代替click作为点击事件. singleTap和doubleTap 分别代表单次点击和双次点击. 二.关于tap的点透处理 在使用zepto框架的tap来移动设备浏览器内的点击事件,来规避click事件的延迟响应时,有可能出现点透的情况,即点击会触发非当前层的点击事件. 处理方式: (1). github上有一个叫做fastclick的库,它也能规避移动设备上clic

移动端web开发常见问题

上一篇总结了一些有关html5和css3的面试题,这一篇是有关于移动端web开发的常见问题,希望一样对你有一些帮助. Meta相关 1. 添加到主屏后的标题(IOS) <meta name="apple-mobile-web-app-title" content="标题"> 2. 启用 WebApp 全屏模式(IOS) 当网站添加到主屏幕后再点击进行启动时,可隐藏地址栏(从浏览器跳转或输入链接进入并没有此效果) <meta name="a