SegmentFault 用户与产品最新的文章
2020-10-10T17:46:33+08:00
https://segmentfault.com/feeds/blogs
https://creativecommons.org/licenses/by-nc-nd/4.0/
HTML元素的height、offsetHeight、clientHeight、scrollTop等梳理
https://segmentfault.com/a/1190000037426695
2020-10-10T17:46:33+08:00
2020-10-10T17:46:33+08:00
caoweiju
https://segmentfault.com/u/caoweiju
2
<h2>关于元素的一些属性</h2><p>在前端的日常开发中,我们经常无可避免的需要获取或者监听一些页面的属性,那么我们需要经常了解一些属性代表的含义才能更好地使用这些属性。特别是一下这些:</p><ol><li>尺寸相关:offsetHeight、clientHeight、scrollHeight;</li><li>偏移相关:offsetTop、clientTop、scrollTop、pageYOffset、scrollY;</li><li>获取相对视口位置:Element.getBoundingClientRect();</li><li>获取元素的style对象:Window.getComputedStyle(Element);</li></ol><h3>属性的定义</h3><p>关于尺寸相关的属性定义:</p><ul><li><p>offsetHeight: Element.offsetHeight是一个只读属性,返回的是元素对应的高度px的值,是一个整数值,不存在小数,</p><ol><li>隐藏元素返回0;</li><li>其他返回:元素的innerHeight + padding + border + margin + 滚动条;但是不包括里面的::before or ::after伪元素;</li></ol></li><li><p>clientHeight: Element.clientHeight是一个只读属性,返回的是元素对应的高度px的值,是一个整数值,不存在小数,</p><ol><li>对于没有设置样式或者inline元素而言,返回的是0,</li><li>对于html元素或者怪异模式下的body,返回的是viewport高度,也就是整个页面视口高度</li><li>其他情况下:元素的innerHeight + padding;不包括border、margin、滚动条;</li></ol></li><li><p>scrollHeight: 是一个只读属性,返回的是元素对应的高度px的值,是一个整数值,不存在小数,</p><ol><li>在子元素不存在滚动情况下,和Element.clientHeight一样</li><li>在子元素存在滚动情况下,会是所以子元素的clientHeight高度之和 + 自身padding;</li></ol></li><li>window.innerHeight: (浏览器窗口高度,不包含工具栏,菜单等,仅仅是可视区域dom的height)</li><li>window.outerHeight: (浏览器窗口高度,包含工具栏、菜单等,整个浏览器的height)</li></ul><p>关于偏移:</p><ul><li>offsetTop:只读属性,返回元素距离最近一个相对定位的父元素内边线的顶部距离,实际使用时可能存在不同样式引起的相对定位父元素不一致的兼容性问题。</li><li>clientTop:上边框的宽度</li><li><p>scrollTop:</p><ol><li>对于滚动元素而言,就是已经滚动的距离,</li><li>对于html而言,就是window.scrollY</li></ol></li><li>window.scrollY,别名:window.pageYOffset,根节点已经垂直滚动的距离</li></ul><h3>开发中所需的相关数据</h3><p>获取整个页面的可视区高度:【不需要可视区外的高度】</p><pre><code>const height = window.innerHeight
|| document.documentElement.clientHeight
|| document.body.clientHeight;</code></pre><p>获取整个页面的高度:【包括可视区外的】</p><pre><code>const height = document.documentElement.offsetHeight
|| document.body.offsetHeight;</code></pre><p>获取整个页面的垂直滚动高度:</p><pre><code>const scrollTop = document.documentElement.scrollTop
|| document.body.scrollTop;</code></pre><p>获取元素相对根节点顶部的距离:</p><pre><code>// 对于相对于根节点定位的元素
const top = Element.offsetTop;
// 对于非相对于根节点定位的元素,需要循环获取
getElementTop(element) {
let actualTop = element.offsetTop
let current = element.offsetParent
while (current !== null) {
actualTop += current.offsetTop
current = current.offsetParent
}
return actualTop
}
// 还有一中方法 滚动距离 + 距离视口上边距
const top = Element.getBoundingClientRect().top + window.scrollY;
</code></pre><p>获取元素相对可视区域顶部距离:</p><pre><code>const top = Element.getBoundingClientRect().top;</code></pre><p>设置整个页面的垂直滚动位置:</p><pre><code>const isCSS1Compat = ((document.compatMode || "") === "CSS1Compat");
if (isCSS1Compat) {
document.documentElement.scrollTop = 100;
} else {
document.body.scrollTop = 100;
}
</code></pre>
点亮contributions--国快乐
https://segmentfault.com/a/1190000020550075
2019-10-02T14:40:54+08:00
2019-10-02T14:40:54+08:00
caoweiju
https://segmentfault.com/u/caoweiju
0
<h2>github 点亮contributions</h2>
<p>在举国同庆的时候,本人根据张大导演的晚会灵感,用宫格来点亮星空,完成大师之作,把github上面的contributions宫格来作为画盘,点缀一番,<a href="https://link.segmentfault.com/?enc=ZXTZMcx9zeFLuU97wDeVuw%3D%3D.KUXA%2BH1%2BApmuR1XYqpl2%2FP%2BfvnBTL1a8FAkrHyzrqEw2CDSMALk7tjTouv3bqsd%2B" rel="nofollow">项目地址</a>,效果如下<em>有点拙劣</em>:</p>
<p><img src="/img/bVbyoaY?w=2880&h=4816" alt="图片描述" title="图片描述"></p>
<p><a href="https://link.segmentfault.com/?enc=%2FcsnKH8P1Q4T3MB3kX696w%3D%3D.5yOU10k83p0mYMuoFct5IX%2FS%2FVFjAB7WsioDb79ZLoUV54bkKui8ge7AnMFHYSkr" rel="nofollow">项目地址</a></p>
翻译:github如何记录contributions
https://segmentfault.com/a/1190000018027139
2019-01-26T00:20:57+08:00
2019-01-26T00:20:57+08:00
caoweiju
https://segmentfault.com/u/caoweiju
0
<h2>github contributions</h2>
<p>一般而言,任何一个人的<code>github</code>主页都有一个这样的方格图;</p>
<p><img src="/img/bVbnNNJ?w=1266&h=298" alt="clipboard.png" title="clipboard.png"></p>
<p>每一个小格代表了<code>one day</code>,不同的颜色深度,代表了不同的<code>contributions</code>次数,那么这个次数是怎么计算的呢?本文的翻译就是上图底部的蓝色链接中的<a href="https://link.segmentfault.com/?enc=LHwBje5Xg9%2FySySE6sRrPQ%3D%3D.LWBjXKYgmX2BedvDxWLrwrMYW1WwM9Uh4hzsUQGYEOGWp0gO%2B8CfhEWBy8hHhLoZDvSe6MMLsbYe%2BmiYY9yULQtpJ4wKDchMIo22p0%2FjDTDW4jROkVHpeFPJPrh9%2BJ8g" rel="nofollow">Learn how we count contributions.</a></p>
<h2>译文正文</h2>
<h3>为什么我的<code>contributions</code>没有在个人<code>profile</code>中体现出来?</h3>
<p>个人<code>profile</code>中的<code>contributions</code>绘图是用于记录个人对<code>github</code>所做的<code>contributions</code>记录,贡献按照协调世界时(UTC)而不是您当地的时区加上时间戳。只有在满足特定标准的情况下才会当做<code>contributions</code>计算;在某些情况下,我们可能需要重建您的<code>contributions</code>绘图才能显示你的<code>contributions</code>。</p>
<h3>没有被记录的<code>contributions</code>
</h3>
<h4>
<code>Issues</code>和<code>pull requests</code>
</h4>
<p>如果<code>Issues</code>和<code>pull requests</code>只有是在独立仓库中操作的,才会显示在您的<code>contributions</code>绘图上,而对于<code>fork</code>的仓库无法被记录的。</p>
<h4><code>Commits</code></h4>
<p>如果<code>Commits</code>符合以下所有条件,则会在您的<code>contributions</code>绘图上显示:</p>
<ul>
<li>用于<code>Commits</code>的电子邮件地址与您的GitHub帐户相关联</li>
<li>
<code>Commits</code>是在独立的仓库中进行的,而不是<code>fork</code>
</li>
<li>
<p><code>Commits</code>在一下条件下完成</p>
<ol>
<li>在仓库的默认分支(通常是<code>master</code>)</li>
<li>在<code>gh-pages</code>分支中(对于具有<code>Project Pages</code>站点的仓库)</li>
</ol>
</li>
</ul>
<p>此外,必须至少满足下列条件之一:</p>
<ul>
<li>你是该仓库的协作者,或者是这个仓库所属组织的一员;</li>
<li>你已经<code>fork</code>了该工程</li>
<li>你对这个仓库提过<code>Issues</code>或者<code>pull requests</code>
</li>
<li>你<code>star</code>加星过这个仓库,</li>
</ul>
<h3>通常的一些没有被记录的原因</h3>
<blockquote>要显示在您的<code>contributions</code>绘图上,共同提交的提交必须符合与一个作者的提交相同的标准。<br>当合并<code>pull requests</code>并且<code>Commit</code>时,只有合并<code>pull requests</code>的用户和打开<code>pull requests</code>的用户才会收到贡献积分。拉取请求的任何其他贡献者都不会获得贡献积分。<br>当重新提交<code>Commit</code>时,<code>Commit</code>的原始作者和重新提交的人,无论是在命令行还是在<code>GitHub</code>上,都会收到贡献信用。</blockquote>
<h4>
<code>Commit</code>是在不到24小时前完成</h4>
<p>在完成符合要求的<code>Commit</code>后,您可能需要等待最多24小时才能看到贡献出现在您的贡献图表上。</p>
<h4>您尚未将本地<code>Git</code>提交电子邮件添加到您的个人资料中</h4>
<p>必须使用已添加到您的GitHub个人资料中的电子邮件地址进行提交,以便显示在您的贡献图表上。您可以通过将.patch添加到提交URL的末尾来检查用于提交的电子邮件地址,例如:<br><a href="https://link.segmentfault.com/?enc=QV0MwP8VL4b6kKJIBIWGNA%3D%3D.upnOHp5LBhL9WDcf2t0UeEz2GKX0nxS7WcB%2Fgg0nOclskFYeVTcOtgJMTznTIPZdR831X65sU8Z9foarz6w26XXtqnTTnKAzmXmRxJVBQpibf8m%2FsGJI4txx6GbqJHN09JEgRriSLlv4QLz6iEaADw%3D%3D" rel="nofollow">https://github.com/octocat/octocat.github.io/commit/67c0afc1da354d8571f51b6f0af8f2794117fd10.patch</a></p>
<pre><code>From 67c0afc1da354d8571f51b6f0af8f2794117fd10 Mon Sep 17 00:00:00 2001
From: The Octocat <octocat@nowhere.com>
Date: Sun, 27 Apr 2014 15:36:39 +0530
Subject: [PATCH] updated index for better welcome message</code></pre>
<p>可以配合:<br>查看email:<code>git config --global user.email </code><br>设置email:<code>git config --global user.email XXXX@gmail.com</code></p>
<h4>未在默认<code>master</code>或<code>gh-pages</code>分支中进行提交</h4>
<p>只有在默认分支(通常为<code>master</code>)或<code>gh-pages</code>分支(对于具有<code>Project Pages</code>站点的存储库)中进行提交时才会计算提交。</p>
<h4>提交共同作者无权访问存储库</h4>
<p>如果在共同作者无权访问的存储库中进行了提交,则该提交将不计入共同作者的贡献。</p>
<h4>提交是在一个<code>fork</code>分支中进行的</h4>
<p>用<code>fork</code>做的提交不会计入你的贡献。要使它们计数,您必须执行以下操作之一:</p>
<ul>
<li>打开<code>pull requests</code>以将更改合并到父存储库中。</li>
<li>要分离<code>fork</code>并将其转换为<code>GitHub</code>上的独立存储库,请联系<code>GitHub</code>支持或<code>GitHub Premium</code>支持。如果<code>fork</code>具有自己的分支,请让支持知道分支是否应随存储库移动到新网络中或保留在当前网络中。</li>
</ul>
<h4>
<code>Commit</code>是在合并和压缩的<code>pull requests</code>中完成的</h4>
<p>合并和压缩的<code>pull requests</code>中的<code>Commit</code>将不计入您的贡献。只有合并<code>pull requests</code>的用户和打开<code>pull requests</code>的用户才会收到贡献积分。拉取请求的任何其他贡献者都不会获得贡献积分。</p>
es6的set和map学习
https://segmentfault.com/a/1190000017782889
2019-01-06T16:57:53+08:00
2019-01-06T16:57:53+08:00
caoweiju
https://segmentfault.com/u/caoweiju
4
<h2>Set</h2>
<p>ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。</p>
<blockquote>因为 Set 中的值总是唯一的,所以需要判断两个值是否相等。在ECMAScript规范的早期版本中,这不是基于和===操作符中使用的算法相同的算法。具体来说,对于 Set s, +0 (+0 严格相等于-0)和-0是不同的值。然而,在 ECMAScript 2015规范中这点已被更改。有关详细信息,请参阅浏览器兼容性 表中的“value equality for -0 and 0”。</blockquote>
<p>另外,NaN和undefined都可以被存储在Set 中, NaN之间被视为相同的值(尽管 NaN !== NaN)。<br>Set本身是一个构造函数,用来生成 Set 数据结构。</p>
<p>Set函数可以接受一个数组(或者具有 iterable 接口的其他数据结构)作为参数,用来初始化。</p>
<pre><code>let b = new Set(['a','b','c','a','b']);
// Set(3) {"a", "b", "c"}</code></pre>
<p>set传入参数也可以一试string;</p>
<pre><code>let a = new Set('aabbcc');
// Set(3) {a,b,c}
</code></pre>
<p>Set 结构的实例有以下属性。</p>
<ul>
<li>Set.prototype.constructor:构造函数,默认就是Set函数。</li>
<li>Set.prototype.size:返回Set实例的成员总数。</li>
</ul>
<p>Set 实例的方法分为两大类:操作方法(用于操作数据)和遍历方法(用于遍历成员)。下面先介绍四个操作方法。</p>
<ul>
<li>add(value):添加某个值,返回 Set 结构本身。</li>
<li>delete(value):删除某个值,返回一个布尔值,表示删除是否成功。</li>
<li>has(value):返回一个布尔值,表示该值是否为Set的成员。</li>
<li>clear():清除所有成员,没有返回值。</li>
</ul>
<p>Array.from方法可以将 Set 结构转为数组。或者是扩展运算符<code>...</code></p>
<pre><code>const items = new Set([1, 2, 3, 4, 5]);
const array = Array.from(items);
const test = [...items];</code></pre>
<h3>遍历操作</h3>
<p>Set 结构的实例有四个遍历方法,可以用于遍历成员。</p>
<ul>
<li>keys():返回键名的遍历器</li>
<li>values():返回键值的遍历器</li>
<li>entries():返回键值对的遍历器</li>
<li>forEach():使用回调函数遍历每个成员</li>
</ul>
<p>由于 Set 结构没有键名,只有键值(或者说键名和键值是同一个值),所以keys方法和values方法的行为完全一致。</p>
<pre><code>let set = new Set(['red', 'green', 'blue']);
for (let item of set.keys()) {
console.log(item);
}
// red
// green
// blue
for (let item of set.values()) {
console.log(item);
}
// red
// green
// blue
for (let item of set.entries()) {
console.log(item);
}
// ["red", "red"]
// ["green", "green"]
// ["blue", "blue"]</code></pre>
<p>Set 结构的实例默认可遍历,它的默认遍历器生成函数就是它的values方法。</p>
<pre><code>Set.prototype[Symbol.iterator] === Set.prototype.values</code></pre>
<p>// true<br>这意味着,可以省略values方法,直接用for...of循环遍历 Set。</p>
<pre><code>let set = new Set(['red', 'green', 'blue']);
for (let x of set) {
console.log(x);
}
// red
// green
// blue</code></pre>
<h2>WeakSet</h2>
<p>WeakSet 结构与 Set 类似,也是不重复的值的集合。但是,它与 Set 有两个区别。</p>
<p>首先,WeakSet 的成员只能是对象,而不能是其他类型的值。</p>
<pre><code>const ws = new WeakSet();
ws.add(1)
// TypeError: Invalid value used in weak set
ws.add(Symbol())
// TypeError: invalid value used in weak set</code></pre>
<p>WeakSet 中的对象都是弱引用,即垃圾回收机制不考虑 WeakSet 对该对象的引用,也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于 WeakSet 之中。</p>
<ul>
<li>WeakSet.prototype.add(value):向 WeakSet 实例添加一个新成员。</li>
<li>WeakSet.prototype.delete(value):清除 WeakSet 实例的指定成员。</li>
<li>WeakSet.prototype.has(value):返回一个布尔值,表示某个值是否在</li>
</ul>
<h2>Map</h2>
<p>JavaScript 的对象(Object),本质上是键值对的集合(Hash 结构),但是传统上只能用字符串当作键。这给它的使用带来了很大的限制。</p>
<p>为了解决这个问题,ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object 结构提供了“字符串—值”的对应,Map 结构提供了“值—值”的对应,是一种更完善的 Hash 结构实现。如果你需要“键值对”的数据结构,Map 比 Object 更合适。</p>
<pre><code>const map = new Map([
['name', '张三'],
['title', 'Author']
]);
map.size // 2
map.has('name') // true
map.get('name') // "张三"</code></pre>
<p>不仅仅是数组,任何具有 Iterator 接口、且每个成员都是一个双元素的数组的数据结构(详见《Iterator》一章)都可以当作Map构造函数的参数。这就是说,Set和Map都可以用来生成新的 Map。</p>
<ul>
<li>Map.prototype.clear()<br>移除Map对象的所有键/值对 。</li>
<li>Map.prototype.delete(key)<br>如果 Map 对象中存在该元素,则移除它并返回 true;否则如果该元素不存在则返回 false</li>
<li>Map.prototype.get(key)<br>返回键对应的值,如果不存在,则返回undefined。</li>
<li>Map.prototype.has(key)<br>返回一个布尔值,表示Map实例是否包含键对应的值。</li>
<li>Map.prototype.keys()<br>返回一个新的 Iterator对象, 它按插入顺序包含了Map对象中每个元素的键 。</li>
<li>Map.prototype.set(key, value)<br>设置Map对象中键的值。返回该Map对象。</li>
</ul>
<p>遍历方法<br>Map 结构原生提供三个遍历器生成函数和一个遍历方法。</p>
<ul>
<li>keys():返回键名的遍历器。</li>
<li>values():返回键值的遍历器。</li>
<li>entries():返回所有成员的遍历器。</li>
<li>forEach():遍历 Map 的所有成员。</li>
</ul>
<h2>WeakMap</h2>
<p>WeakMap与Map的区别有两点。</p>
<p>首先,WeakMap只接受对象作为键名(null除外),不接受其他类型的值作为键名。</p>
chrome插件编写
https://segmentfault.com/a/1190000017513352
2018-12-25T23:06:34+08:00
2018-12-25T23:06:34+08:00
caoweiju
https://segmentfault.com/u/caoweiju
13
<h2>chrome浏览器</h2>
<ol>
<li>
<code>Chrome </code>浏览器追求的是全方位的快速体验。它不仅能飞快地从桌面上启动,而且能瞬间完成网页加载,还能以闪电般的速度运行网络应用。</li>
<li>
<code> Chrome</code> 浏览器整洁且直观。您可在同一位置进行搜索和导航,可随意排列标签页,既快捷又轻松。</li>
<li>您不必成为安全专家即可放心地浏览网络。<code>Chrome </code>默认会为用户提供安全保护,并可供所有人轻松且安全地使用。</li>
</ol>
<h3>内置地址</h3>
<p>所有内置地址列表:<code>chrome://chrome-urls/</code><br>开发者常使用列表:</p>
<ol>
<li>开发者高级选项:<code>chrome://flags/</code>
</li>
<li>
<code>dns</code>缓存清除: <code>chrome://net-internals/#dns</code>
</li>
<li>扩展应用程序:<code>chrome://extensions/</code>
</li>
<li>侦测页面[包括外接安卓设备]:<code>chrome://inspect/#devices</code>
</li>
</ol>
<p>比较全的的列表:</p>
<pre><code>(1)chrome://accessibility/
可达性分析,默认是关闭的,点击accessibility off后变成accessibility on|show accessibility tree,点击show accessibility tree显示分析树
(2)chrome://appcache-internals/
应用程序缓存,显示所有的应用程序缓存路径列表
(3)chrome://apps/
当前chrome安装的应用列表
(4)chrome://blob-internals/
当前内部的blob文件列表
(5)chrome://bookmarks/
书签管理器
(6)chrome://cache/
当前缓存文件的url列表,点击url可以看到对应的缓存文件内容,包括类型 编码 过期时间等概要信息,以及文件内容等具体信息,以二进制方式显示
(7)chrome://chrome/
chrome关于页面,显示当前chrome的版本信息。
(8)chrome://chrome-urls/
显示chrome可用的伪url列表
(9)chrome://components/
显示chrome的组件列表,可以点击"检测是否有更新"来检测当前组件是否有新版本,如果有,可以直接下载更新。
(10)chrome://conflicts/
模块冲突检测,会列出当前已加载到主进程中的所有模块,包括模块的数量、签名方,版本以及模块所在的位置
(11)chrome://copresence/
Google共存信息列表,显示共存信息,包括有效指令、传输的令牌、收到的令牌
(12)chrome://crashes/
显示当前chrome的崩溃报告,需要启用崩溃报告后才会显示。
https://support.google.com/chrome/answer/96817中说明了如何启用崩溃报告。
设置后需要重启chrome才能生效
(13)chrome://credits/
类似于演职员列表,是一份chrome使用的一些开源组件或工具的列表,包括各种工具的主页和授权文件。
但第一行的“Accessibility Audit library, from Accessibility Developer Tools”的主页居然链接的是一份未压缩的js源码,不知道是啥情况
(14)chrome://device-log/
设备日志,chrome://device-log/?refresh=秒数 可以自动刷新
(15)chrome://devices/
显示当前在网络中注册的设备,可以添加打印机到云打印
(16)chrome://discards/
丢弃的标签页面,标签页面按照感兴趣的程度由高到低排序。如果当前的物理内存超出运行内存后,最不感兴趣的tab页面可能被丢弃掉。
(17)chrome://dns/
如果当前显示DNS pre-resolution and TCP pre-connection is disabled.
则打开设置,勾选“预提取资源,以便更快速地加载网页”
然后刷新当前页面就可以看到相关页面预加载的分析数据列表了
(18)chrome://downloads/
下载内容页面
(19)chrome://extensions/
扩展程序列表
(20)chrome://flags/
实验性功能列表,可以在这里启用这些实验性的功能
(21)chrome://flash/
显示flash插件的版本信息,安装位置及显卡的一些具体信息,包括显卡版本号,GPU
(22)chrome://gcm-internals/
GCM(Google Cloud Messaging )内部构建信息,包括签到、连接、注册、发送、接收相关的日志信息。
(23)chrome://gpu/
显示当前的GPU信息,包括图像功能的状态(各种功能的硬件加速)、Gpu内存buffer的状态
(24)chrome://help/
chrome关于页面,与chrome://chrome/是同样的效果
(25)chrome://histograms/
直方图,柱状图,显示了浏览器启动到上一个页面加载的状态统计数据,重新加载可以获取到当前页面加载数据。
(26)chrome://history/
历史记录页面,显示所有的浏览记录
(27)chrome://indexeddb-internals/
显示chrome的内部数据库的实例列表,包括所有的内部数据所在的路径,最后修改时间及数据库大小
(28)chrome://inspect/
检测设备,页面,扩展插件,应用程序等,在Pages标签中显示当前打开的所有tab页面,点击inspect直接跳转到该页面,并调起开发者工具。
(29)chrome://invalidations/
失效的调试信息,失效调试服务状态,注册的失效服务处理器等信息
(30)chrome://local-state/
本地状态,显示的是一个json格式的文件,包括了浏览器的很多状态信息,插件的详细信息
(31)chrome://media-internals/
当前的多媒体内部构建信息,如果当前使用的是浏览器内部的播放器而不是flash播放器的话,会在Players、Audio、Video Capture显示播放文件的详细信息,在Player中可以显示当前播放的适配的详细信息,包括音频、视频及播放器的内部状态信息。
(32)chrome://memory
会自动跳转到chrome://memory-redirect/,显示浏览器占用的总内存以及各个内部进程占用的内存,包括各个Tab页面占用的物理内存和虚拟内存数,包括私有内存,共享内存及总内存
(33)chrome://memory-internals/
内存内部详细信息,点击Update后可以获取到当前浏览内存的使用信息,包括一个json格式的数据。
下发有一个列表,可以显示出所有进程所占用的内存,以及V8引擎使用的和分配的内存。
(34)chrome://nacl/
NaCl的版本信息,包括NaCl的插件位置,版本信息
(35)chrome://net-internals
网络内部构件的信息。包括代理信息、时间信息、DNS信息。其中的DNS可以显示当前浏览器中缓存的DNS信息,包括过期时间
(36)chrome://newtab
打开一个新的标签页
(37)chrome://omnibox/
omnibox 的测试工具 ,omnibox API https://developer.chrome.com/extensions/omnibox
(38)chrome://password-manager-internals/
显示捕获到的密码管理日志。当这个页面被关闭掉,则已有的记录会被清除,并且不再捕获。
(39)chrome://plugins/
显示当前chrome中所使用的插件及版本信息,可以在该页面点击 停用 来停用某个插件
(40)chrome://policy/
显示已设置的政策,默认是没有的
(41)chrome://predictors/
显示预测列表,包括自动完成动作的预取列表,也就是在地址栏输入某些字母后,出现对应的完整地址的列表,还包括
(42)chrome://print/
浏览器打印页面
(43)chrome://profiler/
分析器,可以按照不同的条件分组及排序,主要应该是用于分析chrome的各种进程的内部信息
(44)chrome://quota-internals/
存储空间的配额信息,包括了三个tab页面,Summary、Usage&Quota、Data
Summary标签页显示的是一个磁盘总的空闲空间大小以及混合统计的一些数值
Usage&Quota 标签页显示的是临时的、持久化的和同步的数据库中的具体数据项
Data标签中点击Dump按钮可以生成一个json格式的文件,包含了前面两个tab中的统计信息和分类信息。
(45)chrome://serviceworker-internals/
serviceworker的内部组件,可以勾选选择框,进行调试
ServiceWorker的项目主页: https://www.chromium.org/blink/serviceworker
介绍视频:https://youtu.be/4uQMl7mFB6g
视频中介绍者的的代码:https://github.com/jakearchibald/simple-serviceworker-tutorial
w3c ServiceWorker的Demo:https://github.com/w3c-webmob/ServiceWorkersDemos
(46)chrome://settings/
chrome的设置页面
(47)chrome://signin-internals/
当前chrome登录者信息,包括账户状态的各种信息
(48)chrome://suggestions/
推荐信息,也就是打开新的tab页是默认显示的推荐网站的缩略图页面的那些网站,包含了网站的信息和过期时间。
(49)chrome://sync-internals/
chrome账户同步信息,包含了多个tab页面,首页显示的是同步的概要信息,包含同步相关的各种信息,包括上一次同步的时间,Token请求时间,接收时间等。
后面的tab按照同步的不同类型展示了不同信息,包括了同步的分类、事件等
(50)chrome://system/
系统的诊断数据,包括当前Chrome的版本信息、操作系统的版本信息、同步数据信息、数据压缩代理是否启用、内存使用概况信息、usb键盘检测信息。
(51)chrome://terms/
chrome服务条款
(52)chrome://thumbnails/
顶级网站的url,分为包含缩略图的和未包含的、聚焦和未聚焦,估计也是用于在新开tab页面做推荐时使用
(52)chrome://tracing/
可以在该页面录制chrome的跟踪信息,也可以使用监控
(53)chrome://translate-internals
翻译内部组件信息,此处包含了对于chrome翻译的设置,包括用户自定义的不需要自动翻译的网站列表,可以在此处进行编辑,删除
包括了当前翻译引擎的设置,以及翻译组件的日志信息,日志包括了检测日志、事件日志和错误日志,其中检测日志可以dump为json格式的文件。
追踪日志会将打开该页面后的浏览器访问的网页内容抓取出来,包括要翻译的文字内容列表
(54)chrome://user-actions/
用户操作列表,包括操作类型和发生时间。
(55)chrome://version/
显示当前chrome的版本信息,包括版本号、JavaScript 引擎版本号,Flash插件版本号,用户代理信息等
(56)chrome://view-http-cache/
显示当前http缓存的url列表,点击对应的url,可以打开缓存的文件,包含了文件的具体信息和二进制内容信息
(57)chrome://webrtc-internals/
webrtc内部组件信息。点击Create Dump按钮,可以下载当前的webrtc连接的数据信息和状态信息快照数据
(58)chrome://webrtc-logs/
webrtc日志信息</code></pre>
<h3>应用商店</h3>
<p><a href="https://link.segmentfault.com/?enc=Hu0O79Wa2sNt4ac8NMKhcg%3D%3D.LbXYX9CUGLJOywBlP7%2FGEgf6RfSvmJp7ZUo4ijNEqY2qClpHiYFw8hwwe%2BwLIvHfr0T%2BES%2FAhzyS7CvsZ4%2FNNg%3D%3D" rel="nofollow">扩展应用商店</a><br>包含了很多实用的扩展应用,</p>
<ul>
<li>
<code>adblock</code>,广告过滤<code>开发人员小心你的本地调试代码也被拦截了</code>
</li>
<li>
<code>Momentum</code> 新开页面的美化</li>
<li>
<code>Proxy SwitchyOmega</code> 浏览器代理设置</li>
<li>二维码小助手 当前页面的二维码生成器</li>
<li>捕捉网页截图 - <code>FireShot</code> 滚动全局页面截图</li>
</ul>
<h3>插件编写</h3>
<p>参考<a href="https://link.segmentfault.com/?enc=erDl%2FXGnx1Lr1bMxaXgV1A%3D%3D.2mma6fU%2BveBzNAovjx0AaNvnFyFmlHjvYcj2aCs%2B1ho9bRGjkc3x7X42rJbD%2BaslQ5Ugjp%2BJ%2Fuu6GUac9fbD5w%3D%3D" rel="nofollow">chrome扩展入门</a>编一个入门的插件;</p>
<p>扩展由不同但关联的组件构成。组件可以包括后台脚本,内容脚本,选项页面,UI元素和各种逻辑文件,根据扩展的具体功能加入需要的功能组件模块,其中使用的技术栈就是<code>HTML、JS、CSS</code>,而最后的扩展文件就是压缩的<code>HTML,CSS,JavaScript,图像和Web平台中使用的其他文件</code>得出的包,</p>
<p>扩展具有广泛的功能。他们不仅可以修改用户查看、交互的Web页面内容,甚至可以扩展和更改浏览器本身的行为【所以每个浏览器的扩展可能有点不一样】,</p>
<p>一个常见的<code>chrome扩展</code>会包含一下的一些内容:</p>
<ul>
<li>
<code>manifest.json</code>清单文件【类似配置文件,表明权限、版本、名称、介绍、配置入口等信息】</li>
<li>
<code>ico</code> 【应用扩展商店和chrome浏览器上的工具栏展示的图标】</li>
<li>
<code>Background Script</code> 【后台脚本是扩展的事件处理程序;它包含对扩展重要的浏览器事件的侦听器。它处于休眠状态,直到事件被触发然后执行脚本逻辑。有效的后台脚本仅在需要时加载,在空闲时卸载】</li>
<li>
<code>UI Elements</code> 【UI界面就是正常的html页面,主要是交互中的弹窗等】</li>
<li>
<code>Content Script</code> 【这个就是操作用户打开的页面】</li>
<li>
<code>Options Page</code> 【扩展可供用户配置的页面,用于修改扩展中的一些默认配置参数】</li>
</ul>
<p><img src="/img/bVblDWq?w=388&h=316" alt="clipboard.png" title="clipboard.png"></p>
<h4>一个改变当前查看页面的背景色的扩展插件实现</h4>
<p>想要实现这个功能,很简单就知道需要一下模块:</p>
<ul>
<li>
<code>manifest.json</code> 【配置】</li>
<li>
<code>ico</code> 【图标】</li>
<li>
<code>Background Script</code> 【图标按钮点击交互】</li>
<li>
<code>UI Elements</code> 【点击图标是展示的弹窗页面】</li>
<li>
<code>Options Page</code> 【可供用户选择修改默认的背景色的页面】</li>
<li>
<code>Content Script</code> 【修改用户查看的页面的背景色】</li>
</ul>
<h5><code>manifest.json</code></h5>
<p>配置文件,权限、弹窗页面、ico位置等信息。</p>
<pre><code>{
"name": "Getting Started Example",
"version": "1.0",
"description": "Build an Extension!222",
"permissions": ["activeTab", "declarativeContent", "storage"],
"background": {
"scripts": ["background.js"],
"persistent": false
},
"options_page": "options.html",
"page_action": {
"default_popup": "popup.html",
"default_icon": {
"16": "fh-icon.png",
"32": "fh-icon.png",
"48": "fh-icon.png",
"128": "fh-icon.png"
}
},
"icons": {
"16": "fh-icon.png",
"32": "fh-icon.png",
"48": "fh-icon.png",
"128": "fh-icon.png"
},
"manifest_version": 2
}</code></pre>
<h5><code>background.js</code></h5>
<p>后台脚本,</p>
<pre><code>chrome.runtime.onInstalled.addListener(function() {
chrome.storage.sync.set({color: '#f00'}, function() {
console.log("The color is green.");
});
chrome.declarativeContent.onPageChanged.removeRules(undefined, function() {
chrome.declarativeContent.onPageChanged.addRules([{
conditions: [new chrome.declarativeContent.PageStateMatcher({
pageUrl: {},
})
],
actions: [new chrome.declarativeContent.ShowPageAction()]
}]);
});
});</code></pre>
<h5><code>popup.html</code></h5>
<p>点击ico的时候弹出的页面,只有一个可被点击的色块按钮。</p>
<pre><code><!DOCTYPE html>
<html>
<head>
<style>
button {
height: 30px;
width: 30px;
outline: none;
}
</style>
</head>
<body>
<button id="changeColor"></button>
<script src="popup.js"></script>
</body>
</html></code></pre>
<h5><code>popup.js</code></h5>
<p>弹出页面的交互,点击弹窗页面中的按钮时,需要设置当前展示页面的背景色为<code>chrome.storage</code>存储的默认色值,</p>
<pre><code>let changeColor = document.getElementById('changeColor');
chrome.storage.sync.get('color', function(data) {
changeColor.style.backgroundColor = data.color;
changeColor.setAttribute('value', data.color);
});
changeColor.onclick = function(element) {
let color = element.target.value;
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.executeScript(
tabs[0].id,
{code: 'document.body.style.backgroundColor = "' + color + '";'});
});
};</code></pre>
<h5><code>options.html</code></h5>
<p><a>扩展应用页面</a>可以查看每个扩展的详细介绍,这个页面就是扩展程序的<code>扩展程序选项</code>页面,用户可以自由配置扩展程序需要的参数【前提是扩展应用开发把配置参数放在这个页面供使用者修改了】。本案例是可供选择的背景色值。</p>
<pre><code><!DOCTYPE html>
<html>
<head>
<style>
button {
height: 30px;
width: 30px;
outline: none;
margin: 10px;
}
</style>
</head>
<body>
<div id="buttonDiv">
</div>
<div>
<p>Choose a different background color!</p>
</div>
</body>
<script src="options.js"></script>
</html></code></pre>
<h5><code>options.js</code></h5>
<p><code>扩展程序选项</code>页面的交互脚本,在用户选择 <code>options.html</code>页面中的颜色块的时候,处理设置<code>chrome.storage</code>存储的默认色值,</p>
<pre><code>let page = document.getElementById('buttonDiv');
const kButtonColors = ['#3aa757', '#e8453c', '#f9bb2d', '#4688f1'];
function constructOptions(kButtonColors) {
for (let item of kButtonColors) {
let button = document.createElement('button');
button.style.backgroundColor = item;
button.addEventListener('click', function() {
chrome.storage.sync.set({color: item}, function() {
console.log('color is ' + item);
})
});
page.appendChild(button);
}
}
constructOptions(kButtonColors);</code></pre>
<p>上面实例是chrome官方提供的基础实例,还有很多API需要在使用的时候查看。不能科学上网的话,只能参考一下国内的其他浏览器的扩展开发,其实是类似的,基本都是借鉴的Chrome的方式。</p>
<p>参考:<br><a href="https://link.segmentfault.com/?enc=4veEY1B1v6FRD94rnACFEw%3D%3D.mWb8ezbsB2I6vfMVLgUGKx%2B0kiLJ6toVbc4C2WEDWEgfOSvL5LmfSjEaQ0nNz4mPGdcej4HitG0CgOfRhQOkIQ%3D%3D" rel="nofollow">chrome扩展入门</a><br><a href="https://link.segmentfault.com/?enc=nPv5x%2BwHhDBVOibg9E1VXg%3D%3D.1%2BKu3yqIZrQKNxyovWvalpIvTHfCrDM9MWXySW2uef9H0mDsahC7NTEVKuJP47L%2FnrVj2iadftlBTj9WmDZPSQ%3D%3D" rel="nofollow">chrome扩展综述</a></p>
自闭和标签和伪元素
https://segmentfault.com/a/1190000017392605
2018-12-16T16:37:03+08:00
2018-12-16T16:37:03+08:00
caoweiju
https://segmentfault.com/u/caoweiju
1
<h2>html简史</h2>
<blockquote>HTML 是 Web 统一语言,这些容纳在尖括号里的简单标签,构成了如今的 Web。1991 年,<code>Tim Berners-Lee</code> 编写了一份叫做 “HTML 标签”的文档,里面包含了大约20个用来标记网页的 HTML 标签。他直接借用<code> SGML </code>的标记格式,也就是后来我们看到的 HTML 标记的格式。本文讲述了 HTML 这门 Web 标记语言的发展简史。</blockquote>
<h3>从 IETF 到 W3C: HTML 4 之路</h3>
<ul>
<li>
<code>HTML 1 </code>并不曾存在,</li>
<li>
<code>HTML </code>的第一个官方版本就是由<code> IETF (互联网工程任务组) </code>推出的 <code>HTML 2.0</code>。问世之前,这个版本中的很多细则已经被实现,比如,1994年的 <code>Mosaic 浏览器</code>已经实现了在文档中嵌入图片的方法,后来 <code>HTML 2.0 </code>便吸纳了 <code>img </code>这个标签。</li>
<li>后来,<code>W3C</code> 取代 <code>IETF </code>的角色,成为 HTML 的标准组织,</li>
<li>
<code>90年代的后半叶</code>,HTML 的版本被频繁修改,直到1999年的 <code>HTML 4.01</code>,至此,HTML 到达了它的第一个拐点。</li>
</ul>
<p><code>HTML4</code>之后,出现了一些分歧。</p>
<h3>XHTML 1: XML 风格的 HTML</h3>
<p><code>HTML </code>在<code> HTML 4.01 </code>之后的第一个修订版本就是 <code>XHTML 1.0</code>,其中 X 代表 <code>“eXtensible” </code>,扩展,当然也有人将之解读为 <code>“eXtreme”</code>,极端。<code>XHTML 1.0</code> 是基于<code> HTML 4.01 </code>的,并没有引入任何新标签或属性,唯一的区别是语法,<code>HTML </code>对语法比较随便,而 <code>XHTML</code> 则要求 <code>XML</code> 般的严格语法。</p>
<p> 使用严格的语法规范并非坏事,要求开发者使用单一的代码风格,比如,<code>HTML 4.01 </code>允许你使用大写或小写字母标识标记元素和属性,<code>XHTML</code> 则只允许小写字母。<code>XHTML 1.0</code> 的推出刚好碰上了 <code>CSS </code>的崛起,Web 开发设计者们开始意识到 Web 标准问题,基于 <code>XHTML</code> 的严格语法规范被视为编写<code> HTML</code> 代码的最佳实践。</p>
<p> 于是,W3C 推出 <code>XHTML 1.1</code>。</p>
<p> 如果说<code> XHTML 1.0</code> 是 XML 风格的 HTML,<code>XHTML 1.1 </code>则是货真价实的 <code>XML</code>。这意味着 <code>XHTML 1.1</code> 无法使用 <code>text/html mime-type </code>直接输出,然而,如果 Web 开发者使用 <code>XML mime-type</code>,则当时的主流浏览器,IE 则压根不支持。看上去,W3C 似乎正在与当时的 Web 脱节。</p>
<h3>出力不讨好的 XHTML 2</h3>
<p> 对 W3C 而言,到了 <code>HTML 4</code> 已经是功德圆满,他们的下一步工作是 <code>XHTML 2</code>,希望将 Web 带向 XML 的光明未来。虽然 <code>XHTML 2</code> 听上去和<code> XHTML 1 </code>类似,它们却有很多差别,<code>XHTML 2</code> 不向前兼容,甚至不兼容之前的 HTML。它是一种全新的语言,赤条条来去无牵挂。这实在是一场灾难。</p>
<h3>WHATWG:与 W3C 决裂</h3>
<p> W3C 闭门造车的作风引起了一些人的不满,来自 <code>Opera, Apple, 以及 Mozilla</code> 的代表开始表达反对声音。2004年,Opera 的 <code>Ian Hickson</code> 提议在 HTML 基础上进行扩展以适应新的 Web 应用,该提议遭到 W3C 的拒绝。于是,他们自发组织成立了超文本应用技术工作组,就是 <code>WHATWG</code>。</p>
<h3>从 Web Apps 1.0 到 HTML5</h3>
<p> 从一开始,<code>WHATWG </code>就和<code> W3C </code>走不同的路线,W3C 对问题的讨论是集体投票,而 <code>WHATWG </code>则由主笔<code> Ian Hickson </code>定度。表面上看,W3C 更民主,然而事实上,各种内部纷争会使一些决议限于泥潭,在<code> WHATWG</code>,事情的进展会更容易,不过,主笔的权力并非无限大,他们的委员会可以对那些过于偏执的主笔进行弹劾。</p>
<p> 一开始,<code>WHATWG </code>的主要工作包括两部分,<code>Web Forms 2.0 </code>和 <code>Web Apps 1.0</code>,它们都是 HTML 的扩展,后来,他们合并到一起成为现在的 <code>HTML5</code> 规范。</p>
<h3>言归于好</h3>
<p> 在<code> WHATWG</code> 致力于 <code>HTML5 </code>的同时,W3C 继续他们的 <code>XHTML 2.0</code>,然而,他们慢慢地陷入困境。</p>
<p> 2006年10月,Web 之父 <code>Tim Berners-Lee </code>发表了一篇博客文章,表示,从 HTML 走向 XML 的路是行不通的,几个月后,W3C 组建了一个新的<code> HTML</code> 工作组,他们非常明智地选择了<code> WHATWG </code>的成果作为基础。这一转变带来一些困惑,W3C 同时进行这两套规范,<code>XHTML 2 </code>和<code> HTML 5</code> (<code>注意,W3C 的 HTTML 5 在 5 之前有个空格,而 WHATWG 的 HTML5 则没有空格</code>),而 WHATWG 也在进行着同样的工作。</p>
<h3>XHTML 已死: XHTML 语法永存</h3>
<p> 这一混乱局面到了 2009 年开始变得清晰,W3C 宣布终止 <code>XHTML 2 </code>的工作,这是一份关于<code> XHTML 2 </code>的迟到的讣告。这一消息被那些 XML 的反对者视为珍宝,他们借此嘲笑那些使用 XHTML 1 规范的人,然而他们似乎忘记了,<code>XHTML 1 </code>和 <code>XHTML 2</code> 是截然不同的东西。于此同时,<code>XHTML 1</code> 规范的制定者担心,<code>XHTML 1 </code>中的严格语法规范会被 <code>HTML5 </code>弃用,这种担心后来证明是多余的,<code>HTML5 </code>既支持松散语法,也支持<code> XHTML 1 </code>般的严格语法。</p>
<h3>HTML5 路线图</h3>
<p> <code>HTML5</code> 的现状是,它不再象以前那样让人困惑,然而仍不够明朗。有两个组织在同时制定它的规范,这两个组织有着完全不同的行事风格,<code>WHATWG</code> 是先买后尝,W3C 是先尝后买,他们形成了一个不太靠谱的联姻,最终人们必将面临一个<code> HTML5</code> 还是<code> HTML 5</code> 的问题。<code>html5</code>和其他的不一致的地方,可以查看:<a href="https://link.segmentfault.com/?enc=eChW%2BRDBF1X7u4X%2Bm8yEmw%3D%3D.wSALWZnkA6IJJF7ivj%2BzttRsKxkfe94rCjjzd26%2FfGN2JPo8yZAlW2T5Eu3YeOqZ" rel="nofollow">查看HTML5的区别</a></p>
<h3><!DOCTYPE> 声明</h3>
<p><code><!DOCTYPE></code> 声明位于文档中的最前面的位置,处于 <code><html> </code>标签之前。此标签可告知浏览器文档使用哪种 <code>HTML </code>或 <code>XHTML</code> 规范。<br><code> HTML4</code>的三种模式:<code>HTML 4.01 规定了三种文档类型:Strict、Transitional 以及 Frameset。</code></p>
<p>同样<code>XHTML1</code>也有三种模式:<code>XHTML 1.0 规定了三种 XML 文档类型:Strict、Transitional 以及 Frameset。</code></p>
<p>不过目前而言,在 <code>HTML5</code> 中只有一种声明:<code><!DOCTYPE html></code>,</p>
<p>目前的标准已经到了<code>HTML5</code>的第二版,查看<a href="https://link.segmentfault.com/?enc=mkBox1KjeylWHFoxcLvq%2BQ%3D%3D.o4Ng8QlepqATBddNFeARHtqWl%2FATdhzcIlsgpBl6ajY%3D" rel="nofollow">HTML5.3</a>;</p>
<h3>自闭和标签正确书写</h3>
<p>一般标签由于有开始符号和结束符号,可以在标签内部插入其他标签或文字;自闭合标签由于没有结束符号,没办法在内部插入其他标签或文字,只能定义自身的一些属性。</p>
<p>常见自闭和标签:</p>
<pre><code>1、<meta/>
定义页面的说明信息,供搜索引擎查看。
2、<link/>
用于连接外部的CSS文件或脚本文件。
3、<base/>
定义页面所有链接的基础定位。
4、<br/>
用于换行。
5、<hr/>
水平线。
6、<input/>
用于定义表单元素
7、<img/>
图片</code></pre>
<p>目前的HTML都是准守<code>html5</code>的标准,所以自闭和标签也是需要准守<code>html5</code>的标准写法,也就是推翻了<code>xhtml</code>中的严格模式,自闭和标签不需要加斜杠结束。</p>
<p>图片实例:</p>
<pre><code><img src="" ><img /> // 不规范
<img src="" > // html规范写法
</code></pre>
<h3>伪元素 <code>::placeholder</code>
</h3>
<p>伪元素添加到选择器,但不是描述特殊状态,它们允许您为元素的某些部分设置样式;最为常见的就是<code>::before</code>-<code>::after</code>,</p>
<ul>
<li>::after</li>
<li>::before</li>
<li>::first-letter</li>
<li>::first-line</li>
<li>::selection</li>
</ul>
<p>试验性_内嵌</p>
<ul>
<li>::backdrop</li>
<li>::placeholder</li>
<li>::marker</li>
<li>::spelling-error</li>
<li>::grammar-error</li>
</ul>
<p>对于很多自闭和标签,其实应该是不支持伪元素,不过<code>input</code>元素有一个特殊的伪元素,可以设置占位符的样式;</p>
<pre><code>::-webkit-input-placeholder
::-moz-placeholder
:-ms-input-placeholder
::placeholder</code></pre>
<h3>ios的弹性滚动和滚动条的问题</h3>
<p><code>-webkit-overflow-scrolling: touch</code>; 是用在移动端 <code>webkit</code> 内核浏览器的一个滚动条效果,通常我们的页面滚动(body 会默认采用这种方案无需代码声明)当手指触摸滑动时,它是不会以一种惯性,带回弹效果的滚动,而这段代码即是让它拥有这种像 App 一样的效果</p>
<p>使用这段代码的时候它随即带来了一个问题,<code>-webkit-overflow-scrolling: touch</code>; 所带来的滚动条在未滚动的时候是隐藏状态,而当手指尝试去滑动滚动条就会显示出来,然而这个控件的样式并非像桌面浏览器可以自定义,也就是说无法隐藏。</p>
<p>也就是这两个属性展不兼容。</p>
<pre><code>-webkit-scrollbar{ display: none;}
-webkit-overflow-scrolling: touch;</code></pre>
<p>目前的解决方案:父容器设置固定高度h,并<code>overflow:hidden</code>,滚动容器高出父容器h+10px;滚动容器的子内容高度和父容器一样,比滚动容器小10px,然后滚动条就会被父容器隐藏。</p>
<pre><code><div class="father">
<div class="scroller">
<div class="son">子元素</div>
<div class="son">子元素</div>
<div class="son">子元素</div>
</div>
</div></code></pre>
ecmascript和babel的渊源
https://segmentfault.com/a/1190000017242660
2018-12-04T00:55:53+08:00
2018-12-04T00:55:53+08:00
caoweiju
https://segmentfault.com/u/caoweiju
1
<h2>ecma</h2>
<ul>
<li>中文名: 欧洲计算机制造联合会</li>
<li>外文名: European Computer Manufactures Association</li>
<li>地 区: 日内瓦</li>
<li>缩 写: ECMA</li>
<li>目 的: 信息处理和电信系统</li>
<li>包 括: 程序语言和输入输出</li>
<li>组 织: 国际标准化组织</li>
</ul>
<blockquote>这个组织的目标是评估,开发和认可电信和计算机标准。大家决定把ECMA的总部设在日内瓦是因为这样能够让它与其它与之协同工作的标准制定组织更接近一些,比方说国际标准化组织(ISO)和国际电子技术协会(IEC)。ECMA是“European Computer Manufactures Association”的缩写,中文称欧洲计算机制造联合会。是1961年成立的旨在建立统一的电脑操作格式标准--包括程序语言和输入输出的组织。 <br>主要任务是研究信息和通讯技术方面的标准并发布有关技术报告。ECMA并不是官方机构,而是由主流厂商组成的,他们经常与其他国际组织进行合作。就象ECMA的章程中所说的那样,这个非盈利组织的目标是发展“标准和技术报告以便促进和标准化对信息处理和电信系统的使用过程。</blockquote>
<p>目前已经可以确认的标准:<strong>注:此名单仅部分收录</strong></p>
<pre><code>ECMA-6 7位被编码的字符集(同一样 ISO/IEC 646/ITU-T T.50)
ECMA-13文件结构和标记磁带(最新ISO 1001)
ECMA-35 ISO/IEC 2022年 字符内码
ECMA-43 8位被编码的字符集(和一样ISO/IEC 4873)
ECMA-48 ANSI逃命代码 (和一样ISO/IEC 6429)
ECMA-58 8英寸 软盘
ECMA-59 8英寸 软盘
ECMA-66 5¼-英寸 软盘
ECMA-69 8英寸 软盘
ECMA-70 5¼ -英寸 软盘
ECMA-74信息技术和电信设备散发的空气传播的噪音的测量(和一样ISO 7779)
ECMA-78 5¼ -英寸 软盘
ECMA-94 8位编码字符集(同一样 ISO/IEC 8859-1, -2, -3和-4)
ECMA-99 5¼-英寸1.2兆字节 软盘 (也ISO 8630)
ECMA-100 3½-英寸 软盘 (也ISO 8660)
ECMA-107 文件分配表 (FAT)文件系统
ECMA-113 8位被编码的字符集,拉丁语或斯拉夫(同一样 ISO/IEC 8859-5)
ECMA-114 8位被编码的字符集,拉丁语或阿拉伯语(同一样 ISO/IEC 8859-6)
ECMA-118 8位被编码的字符集,拉丁语或希腊语(同一样 ISO/IEC 8859-7)
ECMA-119 CD-ROM 文件系统(以后被采取 ISO 9660:1988)
ECMA-121 8位被编码的字符集,拉丁语或希伯来语(同一样 ISO/IEC 8859-8)
ECMA-125 3½-英寸 软盘 (也ISO 9529)
ECMA-128 8位被编码的字符集(同一样 ISO/IEC 8859-9)
ECMA-130 CD-ROM 黄皮书
ECMA-139 4mm 数字资料存贮 (二氨基二苯基砜)弹药筒(和一样ISO/IEC 10777)
ECMA-144 8位被编码的字符集(同一样 ISO/IEC 8859-10)
ECMA-146 4mm DAT 数据插件(和一样ISO/IEC 11321)
ECMA-167 普遍盘格式
ECMA-168 ISO 9660 第3级(ISO/IEC 13490)
ECMA-182 周期性多余信息检验 多项CRC-64-ECMA-182
ECMA-234应用程序编程接口为 窗口3.1
ECMA-262 ECMAScript (规范化 脚本(script)语言)
ECMA-334 C#编程语言
ECMA-335 共同语言基础设施
ECMA-340 NFC标准ISO18092(ECMA免费版)
ECMA-352 NFC标准ISO21481(ECMA免费版)
ECMA-357 ECMAScript为XML (E4X)
ECMA-363 通用3D 文件格式
ECMA-365 通用媒体光盘(用于PSP)
ECMA-368 超宽物理和MAC层
ECMA-369 超宽MAC-PHY接口
ECMA-372 C++/CLI
ECMA-376 办公文档开放XML
ECMA-377 200GB的HVD插卡
ECMA-378 100GB的HVD-ROM光碟</code></pre>
<p>而其中就有本文重点介绍的<code>ECMAscript</code>;</p>
<h2>ECMAscript/ES5/ES6/ES20XX</h2>
<p>这里主要简单的介绍一下关于JavaScript的一些历史。</p>
<h3>ECMAscript</h3>
<p><code>ECMAscript</code>是基于<code>Netscape javaScript</code>的一种标准脚本语言。它也是一种基于对象的语言,通过DOM可以操作网页上的任何对象。可以增加、删除、移动或者改变对象。使得网页的交互性大大提高。<a href="https://link.segmentfault.com/?enc=rFOXb2mQ3mywD5pcZ753lA%3D%3D.pziTHEQ4GAsHt6qf%2FoMjJ4iYg%2FTyrvLSVRzNuqbrrh%2FROWQ7Q6Qh8vQGDfsyrqck" rel="nofollow">更多<code>ECMAscript</code>信息和历史</a></p>
<blockquote>ECMAScript是一种由Ecma国际(前身为欧洲计算机制造商协会)通过ECMA-262标准化的脚本程序设计语言。这种语言在万维网上应用广泛,它往往被称为<code>JavaScript</code>或<code>JScript</code>,但实际上后两者是<code>ECMA-262</code>标准的实现和扩展。</blockquote>
<p><code>ECMA</code>的第39号技术专家委员会(Technical Committee 39,简称<code>TC3</code>9)负责制订<code>ECMAScript</code>标准,成员包括<code>Microsoft、Mozilla、Google</code>等大公司。<code>TC39</code>的总体考虑是,ES5与ES3基本保持兼容,较大的语法修正和新功能加入,将由JavaScript.next完成。</p>
<p><strong>了解更多TC39的进度可以关注<a href="https://link.segmentfault.com/?enc=ygN98Z%2FiYQ%2B3DbaNaJLnFg%3D%3D.0%2F2cLb1upK7%2FIhJLUya2aPsY0mivj3Dy%2Fi8zZOQ8Xs8%3D" rel="nofollow">tc39ecma262--github</a>,<a href="https://link.segmentfault.com/?enc=2RkuPzgqxDU6wYhHJHqJYg%3D%3D.bTX3VBxMT4Pd2JlenN8p%2BbbKMUyBsNAk9oqNNgNbYnBsA0kuucvEBik5IFYKDXH9" rel="nofollow">tc39标准进度</a></strong></p>
<h3>ECMAscript/ES历史</h3>
<p><code>ES</code> 是 <code>ECMAScript</code> 的缩写。每次看到 <code>ES</code> 后面跟着数字,是 <code>ECMAScript</code> 的不同版本。实际上一共有 9 个版本【截止时间2018年,2018-11月的部分达到<code>stage4</code>的提案已经作为<code>ES2019</code>的部分了】。我们来深入了解下:</p>
<ol>
<li>
<code>ES1</code>:1997 年 6 月 —— </li>
<li>
<code>ES2</code>:1998 年 6 月 —— </li>
<li>
<code>ES3</code>:1999 年 12月 —— </li>
<li>
<code>ES4</code>:未通过</li>
</ol>
<p>这是前 4 个版本的 <code>ECMAScript</code>,这里简单过一下。仅仅让你知道前 3 个版本每年出一个,而第 4 个版本因为政治因素未通过。</p>
<ul>
<li>
<code>ES5</code>:2009 年 12月:将近 10 年之后,ES5 在 2009 年发布。而下个版本的 ECMAScript 也花了 6 年才发布,【目前<code>ie8</code>还有部分标准没有实现】。</li>
<li>
<p><code>ES6/ES2015</code>:2015 年 6 月:也许困惑就是从这里开始的。你可以看到, ES6 和 ES2015 实际上是同一个东西。<br>起先被推广的名字是 ES6 。然而组委会要求 ECMAScript 必须做到每年做一次更新。由此,这个版本被更名为 ES 2015,且每年都需要更新,并命名为当前年的后缀。</p>
<blockquote>从 2009 年发布的 ES5 到 2015 年发布的 ES6 共经历了 6 年,语言的变化非常大,引入了很多新的语法和特性。为了避免剧烈的变动,从 ES7(2016) 开始,版本发布会变得更加频繁,每次的变动也更小。每年会发布一个新版本,其中包含所有已经完成的特性。</blockquote>
</li>
<li>
<code>ES2016(ES7)</code>:2016 年 6 月:ECMAScript 的第 7 个版本。</li>
<li>
<code>ES2017(ES8)</code>:2017 年 6 月:ECMAScript 的第 8 个版本。</li>
<li>
<code>ES2018(ES9)</code>:2018 年 6 月:ECMAScript 的第 9 个版本。</li>
</ul>
<p><strong>由此可以知道,往后应<code>scma</code>组委会要求,<code>TC39</code>每年都会提交一个版本,可能每年提交的版本修改并不会增加非常多,但还是需要时刻关注</strong></p>
<h3>stage【新增特性过程】</h3>
<p>每一项新特性,要最终纳入 <code>ECMAScript</code> 规范中,<code>TC39</code> 拟定了一个处理过程,称为 <code>TC39 process</code>。其中共包含 5 个阶段,<code>Stage 0 ~ Stage 4</code>,<a href="https://link.segmentfault.com/?enc=B6UypqxCry%2FwdLiNm30IIA%3D%3D.VWj89%2BbRf9z%2BQaUrCqnUL8jfhcE%2BQUUX5ECjcoeknn6tGt4%2F92wqEpIK7b5GHT4Q" rel="nofollow">stage的每个特性所处阶段记录</a>--<a href="https://link.segmentfault.com/?enc=7hNg2whl9h2TI%2Bxtvx7b4Q%3D%3D.heJg4fPVL9dZATRzXwRMMjebBYd5CkIjOE37I9yaF%2F%2F%2Fa2H2k78uJdct2mzKWXlR" rel="nofollow">stage英文文档介绍</a>。</p>
<p><code>TC39</code> 遵循的原则是:分阶段加入不同的语言特性。一旦提案成熟,<code>TC39</code> 会根据提案中的变动来更新规范。直到最近,<code>TC39</code> 依然依赖基于 <code>Microsoft Word</code> 的比较传统的工作流程。但 <code>ES3</code> 出来之后,为了使其达到规范,总共花了十年时间,几乎没有任何改变。之后,ES6 又花了四年才能实现。</p>
<p>自 <code>ES6</code> 出来之后,他们精简了提案的修订过程,以满足现代化开发的需求。新流程使用 <code>HTML </code>的超集来格式化提案。他们使用 <code>GitHub pull requests</code>,这有助于增加社区的参与,并且提出的提案数量也增加了。这个规范现在是一个 <code>living standard</code>,这意味着提案会更快,而且我们也不用等待新版本的规范出来。</p>
<p>新流程涉及五个不同的 <code>Stage</code>。一个提案越成熟,越有可能最终将其纳入规范。</p>
<ol>
<li>
<p><code>Stage 0: strawman</code><br>任何尚未提交作为正式提案的讨论、想法变更或者补充都被认为是第 0 阶段的“稻草人(strawman)”提案。</p>
<blockquote>任何 <code>TC39</code> 成员,或者注册为 <code>TC39</code> 贡献者的会员,都可以提交 <code>Stage 0 </code>的提案。</blockquote>
</li>
<li>
<p>Stage 1: proposal<br>该阶段产生一个正式的提案。确定一个带头人来负责该提案,带头人(或者联合带头人)必须是 TC39 的成员。描述清楚要解决的问题,</p>
<blockquote>解决方案中必须包含例子,<code>API(high level AP)</code> 以及关于相关的语义和算法。潜在问题也应该指出来,例如与其他特性的关系,实现它所面临的挑战。polyfill 和 demo 也是必要的。</blockquote>
</li>
<li>
<p>Stage 2: draft<br><code>Stage 2</code> 的提案应提供规范初稿。此时,语言的实现者开始观察 <code>runtime</code> 的具体实现是否合理。该实现可以使用<code> polyfill</code> 的方式,以便使代码可在<code> runtime </code>中的行为负责规范的定义。<code>javascript </code>引擎的实现为提案提供了原生支持。或者可以 <code>Babel </code>这样的编译时编译器来支持。本草案与最终标准中包含的特性不会有太大差别。草案之后,原则上只接受增量修改。</p>
<blockquote>草案中包含新增特性语法和语义的,尽可能的完善的形式说明,允许包含一些待办事项或者占位符。必须包含 2 个实验性的具体实现,其中一个可以是用转译器实现的,例如 Babel。</blockquote>
</li>
<li>Stage 3: candidate<br><code>Stage 3</code> 提案是建议的候选提案。在这个高级阶段,规范的编辑人员和评审人员必须在最终规范上签字。<code>Stage 3</code> 的提案不会有太大的改变,在对外发布之前只是修正一些问题。规范文档必须是完整的,评审人和 ECMAScript 的编辑要在规范上签字。至少要有 2 个符合规范的具体实现。</li>
<li>
<p>Stage 4: finished<br>最后,当规范的实现至少通过两个验收测试时,提案进入 <code>Stage 4</code>。进入 <code>Stage 4 </code>的提案将包含在 <code>ECMAScript</code> 的下一个修订版中。</p>
<blockquote>通过 Test 262 的验收测试。有 2 个通过测试的实现,以获取使用过程中的重要实践经验。ECMAScript 的编辑必须规范上的签字。规格修订和调度</blockquote>
</li>
</ol>
<p>TC39 打算每年七月向 ECMA 大会提交一份规范批准。以下是生成新规格修订的大致时间表:</p>
<ul>
<li>2月1日:候选草案被生成。</li>
<li>2月-3月:60 天时间进行投票决定草案的去留。</li>
<li>3月 TC39 会议:第 4 阶段的提案被纳入,最终的语义被批准,从 master 新建一个 spec 的分支版本。只有编辑性的改变才能被接受。</li>
<li>4月-6月:ECMA CC 和 ECMA GA 审查期。</li>
<li>7月:由 ECMA 大会批准新标准</li>
</ul>
<p>可以知道,每一年度的版本其实在当年的7-8月份已经基本确定,然后开始下一年的进度。</p>
<p>也正是由于历史原因,有4点需要注意【以下截止时间2018-12,内容会被不断地调整】:</p>
<ol>
<li>
<code>ES5</code>的修改经历了10年,而其中很多都是我们前端经常用到的内容,<code>ES5</code>的修改内容可以参考:<a href="https://link.segmentfault.com/?enc=bKPERJ1n7YJWw5wUjRHQIA%3D%3D.x3KC0ns8CZlxgLYGF%2BLtYhBRS4s1tLVdIZ%2Bs5cM1%2FvAFguQ%2B6TDdHUl%2FbB9QsADgoFQxdbBLts3XwvZGCH8quA%3D%3D" rel="nofollow">Standard ECMA-262, 5.1 Edition / June 2011</a>,由于标准都是向前兼容的,所以这个版本包含了<code>es3</code>之前的标准,<a href="https://link.segmentfault.com/?enc=h6RpF%2FAHRksBDrxdUB80cA%3D%3D.ow34JK%2B19IvfvwpnxE3udaFdAr4PoR%2BKX8RjHbd%2Bw2EkcsY8zdNg4ivdRd1fw%2B04r5L0jhkCRsk1Gp5Bj1WJpQ%3D%3D" rel="nofollow">es5增加的标准列表</a>;</li>
<li>
<code>ES6</code>也是经历了6年时间,在2015年发布的,其中又发生了很多的变化,查看<code>ES6</code>的标准:<a href="https://link.segmentfault.com/?enc=2djzZ6hqQoXO8NcA1NjdoQ%3D%3D.p6iSbA4OviAMVibLPKFje%2Fo6PUxnPIqaCd2k1ApRT2BpxOmTYnLv7Et5UtEJZJQIF7VPP8d2C%2F3OelCvqBtjwg%3D%3D" rel="nofollow">es6标准</a>,通用也是包含了<code>es5</code>和之前的标准,<a href="https://link.segmentfault.com/?enc=w74c9ARHR0BHvXmUe2asew%3D%3D.HDBgnrHx1XdlXnbnxrbhzvv%2FJP9uGroxrEHZ%2BhyYTVcPt6EoJ7nnmpXIXAXqphtzi7mSUYGzSYbbiizrivdNFF%2FX1DUKJa4LFibFpPrp9VA%3D" rel="nofollow">es6增加的标准列表1</a>--<a href="https://link.segmentfault.com/?enc=K94vV70czxHpJWNw29TAZA%3D%3D.DoWryY0oxEjFNcz93q36u8YBBkXFs2ovHaJYo6%2FrrUQPHGsIP2QScthsKxIAdl8sNH7YAjOBxdWH93PwzKNxOioqgzk0NzlaMaxMdD874%2B8%3D" rel="nofollow">es6增加的标准列表1</a>;</li>
<li>为了避免这种较大的改动,<code>TC39</code>将会在每年提交一个版本,这样的变化在2016年开始,而从2016~2018年中的已经完成到<code>stage4</code>的提案列表:<a href="https://link.segmentfault.com/?enc=N%2FH0Gd0GzJlzIWzL3Mhn%2FQ%3D%3D.qLb%2FhdWEfBRVXj%2F1L4M%2FDL0nPWUEEpEee2mQWyYgFbfBb5bzBNrf0oarD1JlN%2Fq9n5nbaAgymxskrapqKMIMnaNa7pu2r0e0D4maxb1WV9o%3D" rel="nofollow">es2016+的已定标准变化</a>;</li>
<li>而每一年的天的各个阶段会有变化,查看当前年份的有效天内容:<a href="https://link.segmentfault.com/?enc=GWrxgF18befAPkGhwxH27g%3D%3D.JBji0%2FVl7oJ16CqxKdFh52%2BjiNX%2BqUw3GD3oxl50StBLm7%2BoK8NuYN3deZAbWsEW" rel="nofollow">当前年份的活跃天stage3~1</a>;</li>
</ol>
<p>标准的发布,各大厂商是需要时间去做实现的,所以如果开发人员想第一时间来体验新的提案带来的便捷,肯定是需要把提案中的内容通过类似<code>polyfill</code>的方式来使用,这就是本文另一个重点<code>babel</code>的作用。</p>
<h2>babel的出现</h2>
<blockquote>Babel 是一个通用的多用途 JavaScript 编译器。通过 Babel 你可以使用(并创建)下一代的 JavaScript,以及下一代的 JavaScript 工具。</blockquote>
<h3>babel简介</h3>
<p>作为一种语言,<code>JavaScript</code> 在不断发展,新的标准/提案和新的特性层出不穷。 在得到广泛普及之前,<code>Babel</code> 能够让你提前(甚至数年)使用它们。</p>
<p>Babel 把用最新标准编写的 <code>JavaScript</code> 代码向下编译成可以在今天随处可用的版本。 这一过程叫做“源码到源码”编译, 也被称为转换编译(transpiling,是一个自造合成词,即转换+编译。以下也简称为转译)。</p>
<p>例如,<code>Babel</code> 能够将新的 <code>ES2015</code> 箭头函数语法:</p>
<pre><code>const square = n => n * n;
// 转译为:
const square = function square(n) {
return n * n;
};</code></pre>
<p>不过 <code>Babel</code> 的用途并不止于此,它支持语法扩展,能支持像 <code>React</code> 所用的 <code>JSX</code> 语法,同时还支持用于静态类型检查的流式语法<code>(Flow Syntax)</code>。</p>
<p>更重要的是,<code>Babel</code> 的一切都是简单的插件,谁都可以创建自己的插件,利用 <code>Babel</code> 的全部威力去做任何事情。</p>
<p>再进一步,<code>Babel</code> 自身被分解成了数个核心模块,任何人都可以利用它们来创建下一代的 <code>JavaScript</code> 工具。</p>
<h3>babel7使用</h3>
<blockquote>由于 JavaScript 社区没有统一的构建工具、框架、平台等等,因此 Babel 正式集成了对所有主流工具的支持。 从 Gulp 到 Browserify,从 Ember 到 Meteor,不管你的环境设置如何,Babel 都有正式的集成支持。</blockquote>
<p>鉴于babel的灵活性,除了配置主流工具<code>webpack</code>、<code>gulp</code>等使用,也可以独自使用;</p>
<ol>
<li>CLI: 使用命令来进行编译</li>
<li>Require hook: 在需要编译的文件中引入<code>require("babel-register");</code>/<code>import "babel-register";</code>来编译当前文件。</li>
</ol>
<p>不过二者都需要配合配置文件<code>.babelrc</code>使用;下面主要示范<code>CLI</code>的使用。</p>
<h4>Babel/CLI</h4>
<p><code>BABEL</code>的 <code>CLI</code> 是一种在命令行下使用 <code>Babel </code>编译文件的简单方法。</p>
<p>让我们先全局安装它来学习基础知识。</p>
<pre><code>$ npm install -D babel-cli</code></pre>
<p>我们可以这样来编译我们的第一个文件:</p>
<pre><code>$ ./node_modules/.bin/babel my-file.js</code></pre>
<p>这将把编译后的结果直接输出至终端。使用 --out-file 或着 -o 可以将结果写入到指定的文件。.</p>
<pre><code>$ ./node_modules/.bin/babel example.js --out-file compiled.js
# 或
$ ./node_modules/.bin/babel example.js -o compiled.js</code></pre>
<p>如果我们想要把一个目录整个编译成一个新的目录,可以使用 --out-dir 或者 -d。.</p>
<pre><code>$ ./node_modules/.bin/babel src --out-dir lib
# 或
$ ./node_modules/.bin/babel src -d lib</code></pre>
<p>一般而言,编译会被放在<code>package.json</code>的<code>scripts</code>字段当中,</p>
<pre><code>"scripts": {
"test": "./node_modules/mocha/bin/mocha",
"build": "./node_modules/.bin/babel src -d lib",
"prepublish": "npm run build"
},</code></pre>
<h4>配置文件<code>.babelrc</code>
</h4>
<pre><code>{
"presets": [
[
"@babel/preset-env",
{
"targets": {
"browsers": [
"last 2 versions",
"safari >= 7"
],
"chrome": 52,
"node": "6.10.0"
},
"modules": "commonjs",
"useBuiltIns": "usage"
}
]
],
"plugins": [
"@babel/plugin-syntax-dynamic-import",
"@babel/plugin-syntax-import-meta",
"@babel/plugin-proposal-class-properties",
"@babel/plugin-proposal-nullish-coalescing-operator",
"@babel/plugin-proposal-do-expressions"
]
}
</code></pre>
<h5>plugins</h5>
<p><a href="https://link.segmentfault.com/?enc=juqhCK8CWJNsvPySLIFTtQ%3D%3D.%2FC%2B31dpKEnbeDizmHmWvzIrtwAbA0U1E3OEBPnCx38GIfHLplt%2FDw%2BPwBj9n3JRB" rel="nofollow">plugins</a>是<code>babel</code>实现<code>es2015+</code>的新的语法,而每实现一种语法的编译,都是一个<code>plugins</code>,</p>
<p>实例:<code>@babel/plugin-transform-arrow-functions</code>可以实现下面这个编译过程。</p>
<pre><code>const square = n => n * n;
// 转译为:
const square = function square(n) {
return n * n;
};</code></pre>
<p>目前的<code>plugins</code>的集合目前可以查看:<a href="https://link.segmentfault.com/?enc=VaQPcJfRi6NQTju5UoVQ4w%3D%3D.ZqOjv3cp2D6MEbPqU7jjZ0X0O%2BHMGSs%2B9v8rgmHAdOvs9YgIYugfE4qGTLwv7oMx" rel="nofollow">babel的plugins集合</a></p>
<h5>@babel/preset-env</h5>
<blockquote>Sidenote, if no targets are specified, @babel/preset-env behaves exactly the same as @babel/preset-es2015, @babel/preset-es2016 and @babel/preset-es2017 together (or the deprecated babel-preset-latest).</blockquote>
<p>可以知道,<code>@babel/preset-env</code>是完成了<code>stage4</code>以内的所有语法,同时添加了更多的配置项;</p>
<pre><code>"presets": [
[
"@babel/preset-env",
{
"targets": {
"browsers": [
"last 2 versions",
"safari >= 7"
],
"chrome": 52,
"node": "6.10.0"
},
"modules": "commonjs",
"useBuiltIns": "usage"
}
]
],</code></pre>
<p>更多的详细信息查看:<a href="https://link.segmentfault.com/?enc=A4ofDhckIQ3A%2FOoRaBAdhw%3D%3D.BBm4orNmdTeERihIXr2ytaHDxnk4aOBd8OGSvqV7N13SGk%2FFZ69620tY9pXOBvI%2F" rel="nofollow">babel的预设使用</a></p>
<p>比较重要的是三个地方:</p>
<ol>
<li>
<code>targets</code>字段:适配所包含的运行环境,根据环境进行打包。</li>
<li>
<code>modules</code>打包后的模块:</li>
<li>
<code>useBuiltIns</code>是<code>polyfill</code>的引入方式,<br>"usage" | "entry" | false, defaults to false.</li>
</ol>
<h5>polyfill</h5>
<p><code>Babel</code> 是处于构建时(也就是传统Java等语言的编译时),转译出来的结果在默认情况下并不包括 ES6 对运行时的扩展,例如,<code>builtins(内建,包括 Promise、Set、Map 等)</code>、内建类型上的原型扩展(如 <code>ES6 对 Array、Object、String 等内建类型原型上的扩展</code>)以及<code>Regenerator</code>(用于<code>generators / yield</code>)等都不包括在内。</p>
<p>需要配合<code>useBuiltIns</code>字段来使用。</p>
<ol>
<li>"useBuiltIns": false<br>不在代码中使用polyfills,表现形式和@babel/preset-latest一样,当使用ES6+语法及API时,在不支持的环境下会报错。</li>
<li>
<p>"useBuiltIns":"entry"<br>在项目入口引入一次(多次引入会报错)</p>
<pre><code>import "@babel/polyfill"
// or
require("@babel/polyfill")</code></pre>
<p>插件@babel/preset-env会将把@babel/polyfill根据实际需求打散,只留下必须的,例如:</p>
<pre><code>// input file
import "@babel/polyfill";</code></pre>
<pre><code>// Out (different based on environment)
import "core-js/modules/es6.promise";
import "core-js/modules/es7.string.pad-start";
import "core-js/modules/es7.string.pad-end";
import "core-js/modules/es7.array.includes";</code></pre>
</li>
<li>
<p>"useBuiltIns":"usage"<br>在文件需要的位置单独按需引入,可以保证在每个bundler中只引入一份。例如:</p>
<pre><code>// In
//a.js
var a = new Promise();
//b.js
var b = new Map();</code></pre>
<pre><code>// Out (if environment doesn't support it)
import "core-js/modules/es6.promise";
var a = new Promise();
import "core-js/modules/es6.map";
var b = new Map();
// Out (if environment supports it)
var a = new Promise();
var b = new Map();</code></pre>
</li>
</ol>
<h3>babel7之前的一些历史</h3>
<p><a href="https://link.segmentfault.com/?enc=W%2B%2BYCMgHFft2ZGzE6Uoubw%3D%3D.Z2HJuyxrMV5iOEX3%2F%2FRRZRtCPQtHICxTyUsuL79vD6wgARELiaQPcgJhXf0osJdR" rel="nofollow">bale7发布</a>;可以说是对以前改变了不少,最为主要的是以下两点:</p>
<h4>babel-preset-es20xx</h4>
<p><a href="https://link.segmentfault.com/?enc=Nw6r8WF7nm5ZrWf8Y78G1Q%3D%3D.D8DOlzAS74XGDIG66GT%2BbTztqnFSXWiUKKX68xHLAGPYxh%2Bf1kseARgh3jgprE63" rel="nofollow">babel-preset-es2015</a>、<a href="https://link.segmentfault.com/?enc=agPlemlN8LqHikLWzeIMDw%3D%3D.ABB7jFyyCiGnJIH0hc4vCTRORFxlZteRzc1bBKT8n7t6iZzcPwa9ZjTvSNprLAYu" rel="nofollow">babel-preset-es2016</a>、<a href="https://link.segmentfault.com/?enc=Y%2BU5jpFYqFPrVnk7CLqU%2FQ%3D%3D.sABvd6b4UPNNlOPhX9i%2B%2B5wVorEL3GgDb91MGgafLwf2OlNnzSUGKHfJBESnHLtQ" rel="nofollow">babel-preset-es2017</a>是<code>babel</code>配合<code>ECMA</code>组委会给<code>TC39</code>的要求,希望<code>ECMA-262</code>能够每年都更新一个版本,所以每年发了一个版本的话,那么<code>babel</code>就会把新的语法创建一个新的预设,以年份命名。</p>
<p>这样看似很好的,不过有一个问题,随着每年的推进,开发者需要每一年就在配置文件中添加一个当年的预设,所以把这些作为<code>stage4</code>以内的完成的ECMA-261提案集合到一个预设<code>@babel/preset-env</code>;而babel只要不停地更新这个预设就可以了。</p>
<h4>stage的移除</h4>
<p>之前提到了,关于<code>TC39</code>的提案进程,有的时候除了<code>stage4</code>的提案外,开发者还想使用其他的进度上的提案,<code>babel</code>使用了<a href="https://link.segmentfault.com/?enc=UJ%2BTAgzSzfWvUNWFFGMl3Q%3D%3D.LrqLpfqowql56B7rwfcDX5jTeDGYkTwLppmKmpsxtFnA6AHcCUZwrNQekTAvpCyP" rel="nofollow">babel-preset-stage-0</a>、<a href="https://link.segmentfault.com/?enc=Ih9%2BRVdjUJN7rdZ6Sht9Ug%3D%3D.F65G34LykJmif%2BDLzlrjs55a8ga2R2faOI9q5izJX6hX2I0cNrzeoJ4Hk%2FhVkQnn" rel="nofollow">babel-preset-stage-1</a>、<a href="https://link.segmentfault.com/?enc=buq8IOwkEJfg3y29k5Xk8w%3D%3D.hzZraMdDE9j6DBkcouN%2Bd2aQEwWcDPoJ2iXNkp6n2C34hZBqEEWyBijm26VYh%2FJY" rel="nofollow">babel-preset-stage-2</a>、<a href="https://link.segmentfault.com/?enc=PSFzwhqzXAX5aIxORo8Gpw%3D%3D.Q6EaNKnhtAyKfBL0O9tsdfklGh8GeTci%2Fbob6GRlqPYS4xU5E6Ckt059wlqOi9a5" rel="nofollow">babel-preset-stage-3</a>这四个预设分别对应四个阶段,</p>
<p>做法看似很好,同样有一个隐患,很多时候,开发者只想使用某一个阶段的提案,而不是把这个阶段的所有提案都引进来,所以<code>babel7</code>的做法是把这个<code>stage-x</code>的预设全都废弃,而是让开发者来进行自己手动将需要的对应阶段的插件引入即可,而不用采用预设的方案,因为预设就是插件的集合。</p>
<p>参考:<br><a href="https://link.segmentfault.com/?enc=M2gsJYmIeHNvHcD9NsWysw%3D%3D.sJ0YCIN2AbezGWzGIauS4dxFfzlGibpdjwhwSkdQg7b8ttUUuTA1U08W88PsPqlHT%2B6aBy3%2BKrJAdQi%2F9JCZGtuAuAEunohfi2ighhUBLR3qkrYTaO5T8q%2F79kc8eMu%2F" rel="nofollow">es简介译文</a><br><a href="https://link.segmentfault.com/?enc=tcHMOxPpchc4elIeUbFRXA%3D%3D.jNeM1FDra7qqVPnXfDadW7y8JUToGUVi9xlh5lBAsbFCPrcazzcOfcEuTgqDTHAQ" rel="nofollow">es个版本的增加项</a><br><a href="https://link.segmentfault.com/?enc=UwI6vD0iemvaBxgwhwrDcA%3D%3D.dc81NpLB8TcOQNMtYygLPqosAulNvOZiez496OC1ygmw1t6PeNOeuXh3QAocbEayLTHtMbjrdbSb1JtqpEh64w%3D%3D" rel="nofollow">es2015的</a><br><a href="https://link.segmentfault.com/?enc=mGQ%2BylxUssWKyy9d8%2B9IUw%3D%3D.OUZjJrUvMM%2F3bCnrhNzvUkgjlBi8tpdFR%2Bwnkod78m3KM%2BbqG7Wcdb%2F2N%2BQhT4y4j771OkNmcBTyFp8TKS%2BAIQ%3D%3D" rel="nofollow">es6增加</a><br><a href="https://link.segmentfault.com/?enc=zFWaNr0sCxZTztk34wd7Ew%3D%3D.Sf0toFfb3AeEtTWu3t%2FzxfP1Xg2Jdn8Ahyg6jQ3JdE0QpQNF7JMb0NKaO2y7ZMFjq2ixAyarqQZU%2FSv9ig83vg%3D%3D" rel="nofollow">es5增加</a><br><a href="https://link.segmentfault.com/?enc=13TGRs8xA7dUyaBO%2Bt3Rqg%3D%3D.JbuOS51J%2F8YrbhBcUMYsfNUFx8Tsv3EuGtzuiSOyzA59pm%2FLrD%2FHqbt7gyCaUPdP4eLIJrwqEorm8lHh5FjPpiApYNibtA7uv6WBNRr2UX4%3D" rel="nofollow">es和ecmascript关系</a><br><a href="https://link.segmentfault.com/?enc=vVNpYMbpvB1Vsp8%2Bsc9V4A%3D%3D.qQF0dD%2FH%2FrI8Z0cut8pMrbavQuVpmhWJoXLUt%2BOV1DkDghM7NCPsSwc564ZE2%2Bol9aJjlzrW2w%2FXi1VyVAo0fw%3D%3D" rel="nofollow">babel预设</a><br><a href="https://link.segmentfault.com/?enc=u1q%2BMGVqI7%2F3wcZh6DiAKQ%3D%3D.56f8h6ozRfK75Ym1T37eTnokS4e%2BtrpVkWR0sDGKoQKjN%2BKwIz7aEblX5rvkOoLWTt8tsqUYrKQCRbSxqNFnkzVsJQ%2BSnTag37y2simJaxd9TnIJX3AeH7kQ2F%2B5Cxy2" rel="nofollow">babel翻译文档</a><br><a href="https://link.segmentfault.com/?enc=8lTnpgKQSNhBKnAZWpY7HA%3D%3D.Nni9MoM4VmbvlwvRf9KSCML5tANkOKm41ErVggYn0POKm8YP9zlhkkpmLCpbLr0s" rel="nofollow">babel使用实例</a><br><a href="https://link.segmentfault.com/?enc=vy7FHhxYD8W1ruU2RnD1nw%3D%3D.E9l13JObA7yADewYsEZ71vNAtoxuIks62YRF1If9BBlZ00Jv2uVkUfYnhPMIvu3nVxWFy0JzIXEnm1lmHzOnnkS3f1Gj%2B6jC2%2F8Lr2mUyEY%3D" rel="nofollow">tc39的进程理解</a><br><a href="https://link.segmentfault.com/?enc=tLqH974Th1KmfD8i6PL98w%3D%3D.CpHQ9oy3zSAYL70VaptseiZ0C0Dapbom2t2XORYObUIFuXj0DhnQ5bUujvu1hKsn" rel="nofollow">plugins必知插件</a></p>
npm包的发布和管理
https://segmentfault.com/a/1190000017099281
2018-11-22T11:03:53+08:00
2018-11-22T11:03:53+08:00
caoweiju
https://segmentfault.com/u/caoweiju
10
<h2>npm包管理</h2>
<p><code>npm</code>其实是<code>Node.js</code>的包管理工具(<code>node package manager</code>)。</p>
<p>为啥我们需要一个包管理工具呢?因为我们在<code>Node.js</code>上开发时,会用到很多别人写的<code>JavaScript</code>代码。如果我们要使用别人写的某个包,每次都根据名称搜索一下官方网站,下载代码,解压,再使用,非常繁琐。于是一个集中管理的工具应运而生:大家都把自己开发的模块打包后放到<code>npm</code>官网上,如果要使用,直接通过npm安装就可以直接用,不用管代码存在哪,应该从哪下载。</p>
<p>更重要的是,如果我们要使用模块A,而模块A又依赖于模块B,模块B又依赖于模块C和模块D,<code>npm</code>可以根据依赖关系,把所有依赖的包都下载下来并管理起来。否则,靠我们自己手动管理,肯定既麻烦又容易出错。</p>
<h3>npm的基础使用</h3>
<p><code>npm</code>的指令其实常用的并不多<a href="https://link.segmentfault.com/?enc=z9DCC2m4yDKZnYx%2F7iX2Uw%3D%3D.0UCWqzvaB4rVcGgwqeR1Bin8shJJFz9kujMjFnXmgCQnfJ51oNvb8bSDuekQyuFH" rel="nofollow">官方文档</a>;列出来如下面:</p>
<ul>
<li>
<code>access</code> <br>Set access level on published packages</li>
<li>
<p><code>adduser</code></p>
<pre><code>Add a registry user account</code></pre>
</li>
<li>
<p><code>audit</code></p>
<pre><code>Run a security audit</code></pre>
</li>
<li>
<p><code>bin</code></p>
<pre><code>Display npm bin folder</code></pre>
</li>
<li>
<p><code>bugs </code></p>
<pre><code>Bugs for a package in a web browser maybe</code></pre>
</li>
<li>
<p><code>build</code></p>
<pre><code>Build a package</code></pre>
</li>
<li>
<p><code>bundle</code></p>
<pre><code>REMOVED *已删除*</code></pre>
</li>
<li>
<p><code>cache</code></p>
<pre><code>Manipulates packages cache</code></pre>
</li>
<li>
<p><code>ci</code></p>
<pre><code>Install a project with a clean slate</code></pre>
</li>
<li>
<p><code>completion </code></p>
<pre><code>Tab Completion for npm</code></pre>
</li>
<li>
<p><code>config</code></p>
<pre><code>Manage the npm configuration files</code></pre>
</li>
<li>
<p><code>dedupe</code></p>
<pre><code>Reduce duplication</code></pre>
</li>
<li>
<p><code>deprecate</code></p>
<pre><code>Deprecate a version of a package</code></pre>
</li>
<li>
<p><code>dist-tag</code></p>
<pre><code>Modify package distribution tags</code></pre>
</li>
<li>
<p><code>docs</code></p>
<pre><code>Docs for a package in a web browser maybe</code></pre>
</li>
<li>
<p><code>doctor</code></p>
<pre><code>Check your environments</code></pre>
</li>
<li>
<p><code>edit</code></p>
<pre><code>Edit an installed package</code></pre>
</li>
<li>
<p><code>explore</code></p>
<pre><code>Browse an installed package</code></pre>
</li>
<li>
<p><code>help-search</code></p>
<pre><code>Search npm help documentation</code></pre>
</li>
<li>
<p><code>help</code></p>
<pre><code>Get help on npm</code></pre>
</li>
<li>
<p><code>hook</code></p>
<pre><code>Manage registry hooks</code></pre>
</li>
<li>
<p><code>init</code></p>
<pre><code>create a package.json file</code></pre>
</li>
<li>
<p><code>install-ci-test</code></p>
<pre><code>Install a project with a clean slate and run tests</code></pre>
</li>
<li>
<p><code>install-test</code></p>
<pre><code>Install package(s) and run tests</code></pre>
</li>
<li>
<p><code>install</code></p>
<pre><code>Install a package</code></pre>
</li>
<li>
<p><code>link</code></p>
<pre><code>Symlink a package folder</code></pre>
</li>
<li>
<p><code>logout </code></p>
<pre><code>Log out of the registry</code></pre>
</li>
<li>
<p><code>ls</code></p>
<pre><code>List installed packages</code></pre>
</li>
<li>
<p><code>npm </code></p>
<pre><code>javascript package manager</code></pre>
</li>
<li>
<p><code>outdated</code></p>
<pre><code>Check for outdated packages</code></pre>
</li>
<li>
<p><code>owner </code></p>
<pre><code>Manage package owners</code></pre>
</li>
<li>
<p><code>pack</code></p>
<pre><code>Create a tarball from a package</code></pre>
</li>
<li>
<p><code>ping</code></p>
<pre><code>Ping npm registry</code></pre>
</li>
<li>
<p><code>prefix</code></p>
<pre><code>Display prefix</code></pre>
</li>
<li>
<p><code>profile</code></p>
<pre><code>Change settings on your registry profile</code></pre>
</li>
<li>
<p><code>prune</code></p>
<pre><code>Remove extraneous packages</code></pre>
</li>
<li>
<p><code>publish </code></p>
<pre><code>Publish a package</code></pre>
</li>
<li>
<p><code>rebuild</code></p>
<pre><code>Rebuild a package</code></pre>
</li>
<li>
<p><code>repo </code></p>
<pre><code>Open package repository page in the browser</code></pre>
</li>
<li>
<p><code>restart</code></p>
<pre><code>Restart a package</code></pre>
</li>
<li>
<p><code>root </code></p>
<pre><code>Display npm root</code></pre>
</li>
<li>
<p><code>run-script</code></p>
<pre><code>Run arbitrary package scripts</code></pre>
</li>
<li>
<p><code>search </code></p>
<pre><code>Search for packages</code></pre>
</li>
<li>
<p>shrinkwrap</p>
<pre><code>Lock down dependency versions for publication</code></pre>
</li>
<li>
<p><code>star</code></p>
<pre><code>Mark your favorite packages</code></pre>
</li>
<li>
<p><code>stars</code></p>
<pre><code>View packages marked as favorites</code></pre>
</li>
<li>
<p><code>start</code></p>
<pre><code>Start a package</code></pre>
</li>
<li>
<p><code>stop</code></p>
<pre><code>Stop a package</code></pre>
</li>
<li>
<p><code>team</code></p>
<pre><code>Manage organization teams and team memberships</code></pre>
</li>
<li>
<p><code>test</code></p>
<pre><code>Test a package</code></pre>
</li>
<li>
<p><code>token</code></p>
<pre><code>Manage your authentication tokens</code></pre>
</li>
<li>
<p><code>uninstall</code></p>
<pre><code>Remove a package</code></pre>
</li>
<li>
<p><code>unpublish</code></p>
<pre><code>Remove a package from the registry</code></pre>
</li>
<li>
<p><code>update</code></p>
<pre><code>Update a package</code></pre>
</li>
<li>
<p><code>version </code></p>
<pre><code>Bump a package version</code></pre>
</li>
<li>
<p><code>view</code></p>
<pre><code>View registry info</code></pre>
</li>
<li>
<p><code>whoami</code></p>
<pre><code>Display npm username
</code></pre>
</li>
</ul>
<h4>init</h4>
<p>初始化创建package.json</p>
<blockquote>npm init [--force|-f|--yes|-y|--scope]<br>npm init <@scope> (same as <code>npx <@scope>/create</code>)<br>npm init [<@scope>/]<name> (same as <code>npx [<@scope>/]create-<name></code>)</blockquote>
<h4>search</h4>
<p>搜索查看远程<code>npm</code>相关资源包信息</p>
<blockquote>npm search [-l|--long] [--json] [--parseable] [--no-description] [search terms ...]<br>aliases: s, se, find</blockquote>
<h4>install</h4>
<p>可以是说是<code>install</code>是最为常见的命令<a href="https://link.segmentfault.com/?enc=4oAymmRUuaJQA%2B24O571Bg%3D%3D.LYDhxi%2B6xTe7eoFh00%2BBvwleIEdekhF%2ByndTICHn1afsWehHfuFQmrUxFebOGF%2BP" rel="nofollow">官方介绍</a>,</p>
<blockquote>npm install (with no args, in package dir)<br>npm install [<@scope>/]<name><br>npm install [<@scope>/]<name>@<tag><br>npm install [<@scope>/]<name>@<version><br>npm install [<@scope>/]<name>@<version range><br>npm install <git-host>:<git-user>/<repo-name><br>npm install <git repo url><br>npm install <tarball file><br>npm install <tarball url><br>npm install <folder> <p>alias: npm i<br>common options: [-P|--save-prod|-D|--save-dev|-O|--save-optional] [-E|--save-exact] [-B|--save-bundle] [--no-save] [--dry-run] </p>
<p>In global mode (ie, with -g or --global appended to the command), it installs the current package context (ie, the current working directory) as a global package. The -g or --global argument will cause npm to install the package globally rather than locally. </p>
<p>The -f or --force argument will force npm to fetch remote resources even if a local copy exists on disk.</p>
</blockquote>
<p>上面的还介绍已经很详细了,所以这里只是讲一下<code>npm install packageName [|--save |--save-prod|--save-dev]</code>的区别;</p>
<ul>
<li>npm install babel <br><a href="https://link.segmentfault.com/?enc=KGTehSzG42BScJRgVGBT8A%3D%3D.%2F7d2InvZs57EVoWswyA%2FcwLOBCdImJVESjmvmozaeblcNLJMxUQXOcQYxxNFWQSt" rel="nofollow">npm5以前</a>,会把X包安装到node_modules目录中,不会修改package.json的dependencies字段,之后运行npm install命令时,不会自动安装X</li>
<li>npm install babel<br><a href="https://link.segmentfault.com/?enc=sJYdGirw9x7oGQXkcL76sA%3D%3D.1IGMw8zs7wsh3HcJU%2FHryjCzVI47QSc62pPhNu2S7prFg5xSc0ooQYk198758tPo" rel="nofollow">npm5以后</a>,会把X包安装到node_modules目录中,会修改package.json的dependencies字段,之后运行npm install命令时,会自动安装X, 线上环境时会被安装</li>
<li>npm install babel -P <br>-P, --save-prod: Package will appear in your dependencies. This is the default unless -D or -O are present. Package will appear in your dependencies, With the --production flag (or when the NODE_ENV environment variable is set to production), npm will install modules listed in dependencies.</li>
<li>npm install babel -D<br>Package will appear in your devDependencies,With the --production flag (or when the NODE_ENV environment variable is set to production), npm will not install modules listed in devDependencies. 会把X包安装到node_modules目录中,会在package.json的devDependencies属性下添加X,之后运行npm install命令时,会自动安装X到node_modules目录中,之后运行npm install –production或者注明NODE_ENV变量值为production时,不会自动安装X到node_modules目录中</li>
</ul>
<h4>update</h4>
<p>升级某个资源包或者全部资源包到某一个版本或者匹配的最新版本。</p>
<blockquote>npm update [-g] [<pkg>...]<br>aliases: up, upgrade</blockquote>
<h4>uninstall</h4>
<p>移除某个资源包</p>
<blockquote>npm uninstall [<@scope>/]<pkg>[@<version>]... [-S|--save|-D|--save-dev|-O|--save-optional|--no-save]<br>aliases: remove, rm, r, un, unlink</blockquote>
<h3>npm包创建、编写、测试、维护</h3>
<p><code>Node</code>出现之前,<code>JavaScript</code>是缺少包结构的。<code>CommonJS</code>致力于改变这种现状,于是定义了包的结构规范。而<code>NPM</code>的出现则是为了在<code>CommonJS</code>规范的基础上,实现解决包的安装卸载,依赖管理,版本管理等问题。<code>require</code>的查找机制明了之后,我们来看一下包的细节。<br>一个符合<code>CommonJS</code>规范的包应该是如下这种结构:</p>
<ul>
<li>一个<code>package.json</code>文件应该存在于包顶级目录下</li>
<li>二进制文件应该包含在<code>bin</code>目录下(可选)</li>
<li>
<code>JavaScript</code>代码入库是<code>index.js</code>,其他包含在<code>lib</code>目录下</li>
<li>文档应该在<code>doc</code>目录下(可选)</li>
<li>单元测试应该在<code>test</code>目录下(可选)</li>
</ul>
<h4>初始化包</h4>
<ol>
<li>
<p>创建包的根目录</p>
<pre><code>mkdir testpackage</code></pre>
</li>
<li>
<p>初始化</p>
<pre><code>npm init // 需要进行一些基本配置</code></pre>
</li>
</ol>
<h4>编写</h4>
<ol>
<li>
<p>创建入口文件</p>
<pre><code>touch index.js</code></pre>
</li>
<li>
<p>编写代码</p>
<pre><code>const updateQueryString = function(url, key, value) {
let urlParts = url.split('#'),
hash = '',
uri = urlParts.shift(),
re = new RegExp(`([?&])${key}=.*?(&|$)`, 'i'),
separator = uri.indexOf('?') !== -1 ? '&' : '?',
encodeKey = encodeURIComponent(key),
encodeValue = encodeURIComponent(value);
urlParts.length > 0 && (hash = `#${urlParts.join('#')}`);
if (uri.match(re)) {
return uri.replace(re, `$1${encodeKey}=${encodeValue}$2`) + hash;
} else {
return `${uri}${separator}${encodeKey}=${encodeValue}${hash}`;
}
};
// 最后的导出部分
module.exports = {
updateQueryString
};</code></pre>
</li>
<li>
<p>测试</p>
<ol>
<li>
<p>创建包的根目录</p>
<pre><code>npm i mocha -D // 安装测试库
npm i chai -D // 安装断言库
mkdir test
cd test
touch index.test.js</code></pre>
</li>
<li>
<p>编写测试代码</p>
<pre><code>const utils = require('./../index.js');
const expect = require('chai').expect;
let {
updateQueryString
} = utils;
describe('updateQueryString函数的测试', function() {
it('https://test.com/path?test=11 修改test参数为22 应该等于 https://test.com/path?test=22', function() {
expect(updateQueryString('https://test.com/path?test=11', 'test', 22)).to.be.equal('https://test.com/path?test=22');
});
});</code></pre>
</li>
<li>
<p>运行测试</p>
<pre><code>cd ..
./node_modules/mocha/bin/mocha </code></pre>
</li>
</ol>
</li>
</ol>
<h3>npm包的发布</h3>
<ol>
<li>注册账号<a href="https://link.segmentfault.com/?enc=5VmNnQFLDD6HnbovEpLhgw%3D%3D.w1Gbnjv6I9GKxF4sbw73Zln8FOk23BdDwMoAliXsM2c%3D" rel="nofollow">npm官网</a>
</li>
<li>终端执行 <code>npm login</code>,输入用户名和密码 、邮箱</li>
<li>
<code>npm publish</code> 发布</li>
</ol>
<h3>Organization包</h3>
<p>我们经常可以看到<code>@angular</code>、<code>@ionic</code>他们的包, 都可以以@开头,那么我们的可不可以,原来<code>angular、ionic</code>都属于一个组织(<code>Organization</code>)只有新创建一个<code>Organization</code>组织之后,才能创建<code>@testorg/testpackname</code>这样的包!!!</p>
<p>那么我们就可以去官网上创建我们的<code>Organization</code>,命名之后,<a href="https://link.segmentfault.com/?enc=aZudp%2FC0dnkf8fXDPIBq%2Fw%3D%3D.weH7oru6TF%2FzEEkNOO%2B%2Bu4OAuCbgbxv4mDWF1duPZYIFByEob5%2BKBTSd2jTla6epZuz08rhacc2MJBnW13aSQKx1wikstTko1lzzBLnJu2o%3D" rel="nofollow">官方步骤</a>,</p>
<ol>
<li>
<p>初始化</p>
<pre><code>npm init --scope=<your_org_name></code></pre>
<blockquote>npm init foo -> npx create-foo<br>npm init @usr/foo -> npx @usr/create-foo<br>npm init @usr -> npx @usr/create</blockquote>
</li>
<li>修改<code>package.json</code>里面的<code>name</code>字段为<code>@your_org_name/<pkg_name></code>
</li>
<li>
<p>发布</p>
<pre><code>npm publish --access public // 公开包发布</code></pre>
</li>
</ol>
<h3>npm包支持esmodule</h3>
<p>使用babel来进行一些现代JavaScript的支持,</p>
<ol>
<li>
<p>创建配置文件</p>
<pre><code>touch .babelrc</code></pre>
</li>
<li>安装先关包</li>
<li>
<p>配置babel</p>
<pre><code>{
"presets": [
[
"@babel/preset-env",
{
"targets": {
"browsers": [
"last 2 versions",
"safari >= 7"
],
"chrome": 52,
"node": "6.10.0"
},
"modules": "commonjs",
"useBuiltIns": "usage"
}
]
],
"plugins": [
"@babel/plugin-syntax-dynamic-import",
"@babel/plugin-syntax-import-meta",
"@babel/plugin-proposal-class-properties",
"@babel/plugin-proposal-json-strings",
[
"@babel/plugin-proposal-decorators",
{
"legacy": true
}
],
"@babel/plugin-proposal-function-sent",
"@babel/plugin-proposal-export-namespace-from",
"@babel/plugin-proposal-numeric-separator",
"@babel/plugin-proposal-throw-expressions",
"@babel/plugin-proposal-export-default-from",
"@babel/plugin-proposal-logical-assignment-operators",
"@babel/plugin-proposal-optional-chaining",
[
"@babel/plugin-proposal-pipeline-operator",
{
"proposal": "minimal"
}
],
"@babel/plugin-proposal-nullish-coalescing-operator",
"@babel/plugin-proposal-do-expressions"
]
}
</code></pre>
</li>
<li>
<p>编译</p>
<pre><code>./node_modules/.bin/babel src -d lib</code></pre>
</li>
</ol>
<p>最后的测试代码地址<a href="https://link.segmentfault.com/?enc=eXI3EUWSFLQt%2FUGdyzwleg%3D%3D.4yQ0DsY%2FI9CkGqnpw%2F9iT%2FdMaPzMJ%2B6U4CpsZoKeQFHl%2F%2FxZwZEZfi028853hZg6" rel="nofollow">test-demo-npm</a></p>
package-lock.json和yarn.lock的包依赖区别
https://segmentfault.com/a/1190000017075256
2018-11-20T15:03:11+08:00
2018-11-20T15:03:11+08:00
caoweiju
https://segmentfault.com/u/caoweiju
30
<h2>node包管理</h2>
<blockquote>包是一段可以复用的代码,这段代码可以从全局注册表下载到开发者的本地环境。每个包可能会,也可能不会依赖于别的包。简单地说,包管理器是一段代码,它可以让你管理依赖(你或者他人写的外部代码),你的项目需要这些依赖来正确运行。</blockquote>
<p>为啥我们需要一个包管理工具呢?因为我们在<code>Node.js</code>上开发时,会用到很多别人写的<code>JavaScript</code>代码。如果我们要使用别人写的某个包,每次都根据名称搜索一下官方网站,下载代码,解压,再使用,非常繁琐。</p>
<p>更重要的是,如果我们要使用模块A,而模块A又依赖于模块B,模块B又依赖于模块C和模块D,<code>npm</code>可以根据依赖关系,把所有依赖的包都下载下来并管理起来。否则,靠我们自己手动管理,肯定既麻烦又容易出错。</p>
<p>于是一个集中管理的工具应运而生:</p>
<ol>
<li>大家都把自己开发的模块打包后放到<code>npm</code>官网上,如果要使用,直接通过<code>npm</code>安装就可以直接用,不用管代码存在哪,应该从哪下载。</li>
<li>
<code>Yarn</code> 是为了弥补<code>npm</code> 的一些缺陷[速度慢,稳定性高]而出现的。”</li>
</ol>
<h3>npm</h3>
<blockquote>
<code>npm</code> 为你和你的团队打开了连接整个 <code>JavaScript</code> 天才世界的一扇大门。它是世界上最大的软件注册表,每星期大约有 30 亿次的下载量,包含超过 600000 个 包(<code>package</code>) (即,代码模块)。来自各大洲的开源软件开发者使用 <code>npm</code> 互相分享和借鉴。包的结构使您能够轻松跟踪依赖项和版本。</blockquote>
<p>下面是关于 <code>npm</code> 的快速介绍:<code>npm</code> 由三个独立的部分组成:</p>
<ul>
<li>网站<br>网站 是开发者查找包(<code>package</code>)、设置参数以及管理 <code>npm</code> 使用体验的主要途径。</li>
<li>注册表(<code>registry</code>)<br>注册表 是一个巨大的数据库,保存了每个包(<code>package</code>)的信息。</li>
<li>命令行工具 (<code>CLI</code>)<br><code>CLI</code> 通过命令行或终端运行。开发者通过 CLI 与 npm 打交道。</li>
</ul>
<h3>yarn</h3>
<p><code>Yarn</code>发布于2016年10月,并在<code>Github</code>上迅速拥有了2.4万个Star。而<code>npm</code>只有1.2万个<code>star</code>。这个项目由一些高级开发人员维护,包括了<code>Sebastian McKenzie</code>(Babel.js)和<code>Yehuda Katz</code>(Ember.js、Rust、Bundler等)。</p>
<blockquote>
<code>Yarn</code>一开始的主要目标是解决上一节中描述的由于语义版本控制而导致的npm安装的不确定性问题。虽然可以使用<code>npm shrinkwrap</code>来实现可预测的依赖关系树,但它并不是默认选项,而是取决于所有的开发人员知道并且启用这个选项。<br>Yarn采取了不同的做法。每个<code>yarn</code>安装都会生成一个类似于<code>npm-shrinkwrap.json</code>的<code>yarn.lock</code>文件,而且它是默认创建的。除了常规信息之外,<code>yarn.lock</code>文件还包含要安装的内容的校验和,以确保使用的库的版本相同。</blockquote>
<p>yarn的优化主要体现在:</p>
<ol>
<li>
<p>速度快 :</p>
<ul>
<li>并行安装:无论 npm 还是 Yarn 在执行包的安装时,都会执行一系列任务。npm 是按照队列执行每个 package,也就是说必须要等到当前 package 安装完成之后,才能继续后面的安装。而 Yarn 是同步执行所有任务,提高了性能。</li>
<li>离线模式:如果之前已经安装过一个软件包,用Yarn再次安装时之间从缓存中获取,就不用像npm那样再从网络下载了。</li>
</ul>
</li>
<li>安装版本统一:为了防止拉取到不同的版本,<code>Yarn</code> 有一个锁定文件 (lock file) 记录了被确切安装上的模块的版本号。每次只要新增了一个模块,Yarn 就会创建(或更新)<code>yarn.lock</code> 这个文件。这么做就保证了,每一次拉取同一个项目依赖时,使用的都是一样的模块版本。</li>
<li>更好的语义化: <code>yarn</code>改变了一些<code>npm</code>命令的名称,比如 <code>yarn add/remove</code>,感觉上比 npm 原本的 <code>install/uninstall</code> 要更清晰。</li>
</ol>
<h3>node包的安装</h3>
<ol>
<li>
<p>执行工程自身 <code>preinstall</code></p>
<ul><li>当前 npm 工程如果定义了<code> preinstall</code> 钩子此时会被执行。</li></ul>
</li>
<li>
<p>确定首层依赖</p>
<ul><li>模块首先需要做的是确定工程中的首层依赖,也就是 <code>dependencies</code> 和 <code>devDependencies</code> 属性中直接指定的模块(假设此时没有添加 <code>npm install</code> 参数)。工程本身是整棵依赖树的根节点,每个首层依赖模块都是根节点下面的一棵子树,npm 会开启多进程从每个首层依赖模块开始逐步寻找更深层级的节点。</li></ul>
</li>
<li>
<p>获取模块</p>
<ul>
<li>获取模块是一个递归的过程,分为以下几步:</li>
<li>获取模块信息。在下载一个模块之前,首先要确定其版本,这是因为 <code>package.json</code> 中往往是 <code>semantic version</code>(semver,语义化版本)。此时如果版本描述文件(<code>npm-shrinkwrap.json</code> 或 <code>package-lock.json</code>)中有该模块信息直接拿即可,如果没有则从仓库获取。如<code> packaeg.json</code> 中某个包的版本是 <code>^1.1.0,npm</code> 就会去仓库中获取符合 <code>1.x.x</code> 形式的最新版本。</li>
<li>获取模块实体。上一步会获取到模块的压缩包地址(<code>resolved</code> 字段),npm 会用此地址检查本地缓存,缓存中有就直接拿,如果没有则从仓库下载。</li>
<li>查找该模块依赖,如果有依赖则回到第1步,如果没有则停止。</li>
</ul>
</li>
<li>
<p>模块扁平化(<code>dedupe</code>)</p>
<ul><li>上一步获取到的是一棵完整的依赖树,其中可能包含大量重复模块。比如 A 模块依赖于 <code>loadsh</code>,B 模块同样依赖于 <code>lodash</code>。在 npm3 以前会严格按照依赖树的结构进行安装,因此会造成模块冗余。<code>yarn</code>和从 <code>npm5</code> 开始默认加入了一个 <code>dedupe</code> 的过程。它会遍历所有节点,逐个将模块放在根节点下面,也就是<code> node-modules</code> 的第一层。当发现有重复模块时,则将其丢弃。这里需要对重复模块进行一个定义,它指的是模块名相同且 <code>semver</code> 兼容。每个 <code>semver</code> 都对应一段版本允许范围,如果两个模块的版本允许范围存在交集,那么就可以得到一个兼容版本,而不必版本号完全一致,这可以使更多冗余模块在 <code>dedupe</code> 过程中被去掉。</li></ul>
</li>
<li>
<p>安装模块</p>
<ul><li>这一步将会更新工程中的<code>node_modules</code>,并执行模块中的生命周期函数(按照 <code>preinstall、install、postinstall</code> 的顺序)。</li></ul>
</li>
<li>
<p>执行工程自身生命周期</p>
<ul><li>当前 npm 工程如果定义了钩子此时会被执行(按照 <code>install、postinstall、prepublish、prepare</code> 的顺序)。</li></ul>
</li>
</ol>
<h3>包依赖关系</h3>
<p>我们要使用模块A,而模块A又依赖于模块B,模块B又依赖于模块C和模块D,npm可以根据依赖关系,把所有依赖的包都下载下来并管理起来,而这种依赖又有不一样的表现形式。</p>
<ol>
<li>嵌套依赖</li>
<li>扁平依赖</li>
</ol>
<h4>嵌套依赖</h4>
<p>假设目前工程依赖 A, B, C 三个库,而他们对某个库 <code>somelib</code> 存在这样的依赖关系:</p>
<pre><code>A - somelib 1.4.x
B - somelib 1.6.x
C - somelib 1.6.x</code></pre>
<p>如果要安装 ABC 三个库,那么 <code>somelib</code> 会存在版本冲突。<code>npm5+/yarn</code> 会在实际安装时,给三个库分别下载各自依赖的 <code>somelib</code> 版本。假设 npm 先安装了 A, 由于 A 依赖<code> somelib 1.4.x</code> 版本,那么 自身依赖先安装<code>1.4.x </code>。再安装 B, C 时,由于 B, C 依赖的都不是<code> 1.4.x</code>, 于是安装完之后,关系就变成这个样子了:</p>
<pre><code>node_modules
├── A
│ └── node_modules
│ └── somelib 1.4.x
├── B
│ └── node_modules
│ └── somelib 1.6.x
└── C
└── node_modules
└── somelib 1.6.x</code></pre>
<p>这样就是嵌套依赖。<br>很显然这种方式很大的浪费了磁盘空间。</p>
<h4>扁平依赖</h4>
<p>当关联依赖中包括对某个软件包的重复引用,在实际安装时将尽量避免重复的创建。</p>
<p>假设目前工程依赖 A, B, C 三个库,而他们对某个库 <code>somelib</code> 存在这样的依赖关系:</p>
<pre><code>A - somelib 1.4.x
B - somelib 1.6.x
C - somelib 1.6.x</code></pre>
<p>如果要安装 ABC 三个库,那么 <code>somelib</code> 会存在版本冲突。<code>npm5+/yarn</code> 会在实际安装时,给三个库分别下载各自依赖的 <code>somelib</code> 版本。假设 npm 先安装了 A, 由于 A 依赖<code> somelib 1.4.x</code> 版本,那么 <code>1.4.x </code>会变成主版本。再安装 B, C 时,由于 B, C 依赖的都不是<code> 1.4.x</code>, 于是安装完之后,关系就变成这个样子了:</p>
<pre><code>node_modules
├── A
├── somelib 1.4.x
├── B
│ └── node_modules
│ └── somelib 1.6.x
└── C
└── node_modules
└── somelib 1.6.x</code></pre>
<p>这样就是扁平依赖。</p>
<blockquote>需要注意的是,明明 B, C 都依赖 1.6.x 版本,实际上 <code>npm5+/yarn</code> 却要把这个版本保存两次,这样明显是对磁盘空间的浪费。我们把这种情况就称为不完全扁平的。目前这种情况还无法安全解决。</blockquote>
<h3>lock文件</h3>
<blockquote>锁文件是由包管理器自动生成的。它包含了重现全部的依赖源码树需要的所有信息、你的项目依赖中的所有信息,以及它们各自的版本。</blockquote>
<p>现在值得强调的是,<code>Yarn</code> 使用了锁文件,而<code> npm5</code>以前没有默认锁文件,<code>npm5</code>之后加入了默认锁文件功能。我们会谈到这种差别导致的一些后果。既然我已经向你介绍了包管理器这部分,现在我们来讨论依赖本身。</p>
<p>目前常见的两种lock文件:</p>
<ol>
<li>
<code>packahe-lock.json</code> 是npm5之后默认生成的锁文件</li>
<li>
<code>yarn.lock</code> 是yarn的锁文件</li>
</ol>
<h4>packahe-lock.json解析</h4>
<pre><code>{
"name": "package-name",
"version": "1.0.0",
"lockfileVersion": 1,
"dependencies": {
"cacache": {
"version": "9.2.6",
"resolved": "https://registry.npmjs.org/cacache/-/cacache-9.2.6.tgz",
"integrity": "sha512-YK0Z5Np5t755edPL6gfdCeGxtU0rcW/DBhYhYVDckT+7AFkCCtedf2zru5NRbBLFk6e7Agi/RaqTOAfiaipUfg=="
},
"duplexify": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.5.0.tgz",
"integrity": "sha1-GqdzAC4VeEV+nZ1KULDMquvL1gQ=",
"dependencies": {
"end-of-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.0.0.tgz",
"integrity": "sha1-1FlucCc0qT5A6a+GQxnqvZn/Lw4="
},
}
}
}</code></pre>
<p>可以看出来,package-lock.json把所有的包的依赖顺序列出来,第一次出现的包名会提升到顶层,后面重复出现的将会放入被依赖包的node_modules当中。引起不完全扁平化问题。</p>
<h4>yarn.lock解析</h4>
<pre><code># THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
package-1@^1.0.0:
version "1.0.3"
resolved "https://registry.npmjs.org/package-1/-/package-1-1.0.3.tgz#a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0"
package-2@^2.0.0:
version "2.0.1"
resolved "https://registry.npmjs.org/package-2/-/package-2-2.0.1.tgz#a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0"
dependencies:
package-4 "^4.0.0"
package-3@^3.0.0:
version "3.1.9"
resolved "https://registry.npmjs.org/package-3/-/package-3-3.1.9.tgz#a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0"
dependencies:
package-4 "^4.5.0"
package-4@^4.0.0, package-4@^4.5.0:
version "4.6.3"
resolved "https://registry.npmjs.org/package-4/-/package-4-2.6.3.tgz#a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0"</code></pre>
<p>显然yarn.lock锁文件把所有的依赖包都扁平化的展示了出来,对于同名包但是semver不兼容的作为不同的字段放在了yarn.lock的同一级结构中。</p>
<h3>验证实例</h3>
<p>在一个测试package工程里面,安装了以下三个包,安装了react-router 3.2.1,另外安装了react-router-dom 4.3.1 和react-router-native 4.3.0,这两个都依赖"react-router": "^4.3.0",结果如下:<br>.<br>└── node_modules</p>
<pre><code>├── react-router-dom4.3.1
│ └── react-router4.3.1
├── react-router-native4.3.0
│ └── react-router4.3.1
└── react-router3.2.1
</code></pre>
<p>查看package-lock.json结果和最后node_modules安装结果:</p>
<p><img src="/img/bVbjN9R?w=2024&h=2010" alt="clipboard.png" title="clipboard.png"><br><img src="/img/bVbjObA?w=2588&h=2080" alt="图片描述" title="图片描述"></p>
<p>查看yarn.lock结果和最后node_modules安装结果:</p>
<p><img src="/img/bVbjObP?w=2044&h=2034" alt="图片描述" title="图片描述"></p>
<p><img src="/img/bVbjObV?w=2304&h=2808" alt="图片描述" title="图片描述"></p>
<p><a href="https://link.segmentfault.com/?enc=DmRz%2BnKUJKHN5mOpRw1ljA%3D%3D.5uyNQZ%2BoiCVGGHPXhco1rLrdMERbzyaVgopP9G3Fr0ZudkBzSvqELbuVJcFG9kIJ9%2BT4PxnRKUPRFvzBwtDK9g%3D%3D" rel="nofollow">lock官方介绍</a><br><a href="https://link.segmentfault.com/?enc=PlORIIGiz5CaGB3nY5vYFA%3D%3D.Xb9DZKSiGSD5C4wI6Boa%2FoW%2Bk29hPOgrK72pPFwVemNEfFxtvpDIJqPCSZ%2BHX%2BU9" rel="nofollow">理解 NPM 5 中的 lock 文件</a><br><a href="https://link.segmentfault.com/?enc=Dg0KSrV%2FVWXwFm7mlN1%2BBQ%3D%3D.uLBzDnyIacBGxqRZFREkVOAs%2B7ef2wzvYm7y4%2FCxfbOnSak%2FXmznx14UOU051Y1A" rel="nofollow">知乎问答1</a><br><a href="https://link.segmentfault.com/?enc=kK%2B8ZnH5mOo%2FcjEhFONxKQ%3D%3D.KFTN%2Fb3XoEZMXpbFulSu4HK%2FBVXi2G2kf4kap5hUIvLnHW%2FVM0Cx5tE8ShM3zwKlwu3fYKSt5fW2fYZHqIvAIw%3D%3D" rel="nofollow">知乎问答2</a></p>
preload、prefetch的认识
https://segmentfault.com/a/1190000016955899
2018-11-08T23:46:43+08:00
2018-11-08T23:46:43+08:00
caoweiju
https://segmentfault.com/u/caoweiju
18
<h2>预加载</h2>
<p>现在的网络情况虽然很乐观,但是</p>
<h3>defer和async</h3>
<p>当浏览器碰到 script 脚本的时候:</p>
<p><code><script src="script.js"></script></code></p>
<p>没有 defer 或 async,浏览器会立即加载并执行指定的脚本,“立即”指的是在渲染该 script 标签之下的文档元素之前,也就是说不等待后续载入的文档元素,读到就加载并执行。</p>
<p><code><script async src="script.js"></script></code></p>
<p>有 async,加载和渲染后续文档元素的过程将和 script.js 的加载与执行并行进行(异步)。</p>
<p><code><script defer src="myscript.js"></script></code></p>
<p>有 defer,加载后续文档元素的过程将和 script.js 的加载并行进行(异步),但是 script.js 的执行要在所有元素解析完成之后,DOMContentLoaded 事件触发之前完成。</p>
<p>然后从实用角度来说呢,首先把所有脚本都丢到 </body> 之前是最佳实践,因为对于旧浏览器来说这是唯一的优化选择,此法可保证非脚本的其他一切元素能够以最快的速度得到加载和解析。</p>
<p>接着,我们来看一张图咯:</p>
<p><img src="/img/bVMJDk?w=689&h=112" alt="clipboard.png" title="clipboard.png"></p>
<p>此图告诉我们以下几个要点:</p>
<ol>
<li>defer 和 async 在网络读取(下载)这块儿是一样的,都是异步的(相较于 HTML 解析)</li>
<li>它俩的差别在于脚本下载完之后何时执行,显然 defer 是最接近我们对于应用脚本加载和执行的要求的</li>
<li>关于 defer,此图未尽之处在于它是按照加载顺序执行脚本的,这一点要善加利用</li>
<li>async 则是一个乱序执行的主,反正对它来说脚本的加载和执行是紧紧挨着的,所以不管你声明的顺序如何,只要它加载完了就会立刻执行</li>
<li>仔细想想,async 对于应用脚本的用处不大,因为它完全不考虑依赖(哪怕是最低级的顺序执行),不过它对于那些可以不依赖任何脚本或不被任何脚本依赖的脚本来说却是非常合适的,</li>
</ol>
<h3>preload和refetch</h3>
<p><code>preload</code>通常在页面中,我们需要加载一些脚本和样式,而使用 preload 可以对当前页面所需的脚本、样式等资源进行预加载,而无需等到解析到 script 和 link 标签时才进行加载。这一机制使得资源可以更早的得到加载并可用,且更不易阻塞页面的初步渲染,进而提升性能。</p>
<p>使用方式<br>将 link 标签的 rel 属性的值设为 preload,as 属性的值为资源类型(如脚本为 script,样式表为 style)</p>
<pre><code><head>
<meta charset="utf-8">
<title>preload example</title>
<!-- 对 style.css 和 index.js 进行预加载 -->
<link rel="preload" href="style.css" as="style">
<link rel="preload" href="index.js" as="script">
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="app"></div>
<script src="index.js"></script>
</body></code></pre>
<p><code>prefetch</code>与 <code>preload</code> 一样,都是对资源进行预加载,但是 prefetch 加载的资源一般不是用于当前页面的,即未来很可能用到的这样一些资源,简单点说就是其他页面会用到的资源。当然,prefetch 不会像 preload 一样,在页面渲染的时候加载资源,而是利用浏览器空闲时间来下载。当进入下一页面,就可直接从 disk cache 里面取,既不影响当前页面的渲染,又提高了其他页面加载渲染的速度。</p>
<p>使用方式<br>同 <code>preload</code> 很相似,无需指定 as 属性:</p>
<pre><code><head>
<meta charset="utf-8">
<title>preload example</title>
<!-- 对 style.css 和 index.js 进行 preload 预加载 -->
<link rel="preload" href="style.css" as="style">
<link rel="preload" href="index.js" as="script">
<!-- 对资源进行 prefetch 预加载 -->
<link rel="prefetch" href="next.css">
<link rel="prefetch" href="next.js">
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="app"></div>
<script src="index.js"></script>
</body></code></pre>
<p><strong>总结:对当前页面需要的资源,使用 preload 进行预加载,对其它页面需要的资源进行 prefetch 预加载。</strong></p>
<h3>Subresource和Prerender</h3>
<p><code>subresource</code>可以用来指定资源是最高优先级的。比如,在Chrome和Opera中我们可以加上下面的代码:</p>
<p><code><link rel="subresource" href="styles.css"></code></p>
<blockquote>Chromium的文档这么解释:<br>和 "Link rel=prefetch"的语义不同,"Link rel=subresource"是一种新的连接关系。rel=prefetch指定了下载后续页面用到资源的低优先级,而rel=subresource则是指定当前页面资源的提前加载。</blockquote>
<p>所以,如果资源是在当前页面需要,或者马上就会用到,则推荐用subresource,否则还是用prefetch。</p>
<p><code>prerender</code>是一个重量级的选项,它可以让浏览器提前加载指定页面的所有资源。</p>
<p><code><link rel="prerender" href="/thenextpage.html" /></code></p>
<blockquote>Steve Souders的文章详细解释了这个技术:<br>prerender就像是在后台打开了一个隐藏的tab,会下载所有的资源、创建DOM、渲染页面、执行JS等等。如果用户进入指定的链接,隐藏的这个页面就会进入马上进入用户的视线。Google Search多年前就利用了这个特性实现了Instant Pages功能。微软最近也宣布会让Bing在IE11上用类似prerender的技术。</blockquote>
<p>但是要注意,一定要在十分确定用户回点某个链接时才用这个特性,否则客户端就会无端的下载很多资源和渲染这个页面。<br>正如任何提前的动作一样,预判总是有一定风险出错。如果提前的动作是昂贵的(比如高CPU、耗电、占用带宽),就要谨慎使用了。虽然不容易预判用户会点进哪个页面,但还是存在一些典型的场景:</p>
<p>如果用户搜索到了一个明显正确的结果时,那么这个页面就很有可能被点入<br>如果用户在登录页面,那么登录成功后的页面就很可能接下来会被加载了<br>如果用户在阅读一个多页面的文章或者有页码的内容时,下一页就很可能会马上被点击了<br>利用Page Visibility API可以用来防止页面在还没真正展示给用户时就触发了JS的执行。</p>
<p>参考:<br><a href="https://segmentfault.com/q/1010000000640869">defer和async</a><br><a href="https://segmentfault.com/a/1190000016949393">prefetch与 preload</a><br><a href="https://link.segmentfault.com/?enc=IGSh%2BtPx4UojsA3Aur2%2BrA%3D%3D.rq7rEydHrThCl0zYODuZ7S4C90nUmkKKIjM%2BHDdhEJYxCfzGMGFhz9H%2F9BqG%2FLP%2Bqn82FipDtTpAhJ9eYh1Rj2IVRuTCK3ayV8Sy2fYfdA0%3D" rel="nofollow">prefetch预加载</a><br><a href="https://link.segmentfault.com/?enc=jq1fGatggs3GmMmSZkT1FQ%3D%3D.spTfDmJojiXrPwADeOBhjrwSPtwijYyk1CmD3yyiK8GRCzONAFZKcRoQTsg77SuQUJ8U0NteT%2BVtpccD1%2FSa7ywRp4dbA9JWvVQhXw13K5c%3D" rel="nofollow">preload当即加载</a><br><a href="https://link.segmentfault.com/?enc=Z1VGkQRYSkAQ1b5grCEpJQ%3D%3D.w7y7UHM2F5iK0dJqCShAR6WnPSJlWbC4qF616ftWGeVB5mNQaDNbome8G7kSfJk%2FCeQBSf1lkwHbffeFXrqrIpeTdkDZHY2WWiXx4JHa%2FuE%3D" rel="nofollow">加载技术概述</a><br><a href="https://link.segmentfault.com/?enc=lvGJJO7lYzevMfoYaZWotw%3D%3D.FzJeLvrLL98zwWHJwOekq6mKj9%2Fhi6TQWsgwtpzUwOFTQfT9xTf%2B0HI5Ql0m%2BI11z0Iw5lJnRkF2k5I4AP6kk8DZisz7qjyulNtbSAfDgNs%3D" rel="nofollow">dnc fetch</a></p>
<p>Prerender Subresource</p>
HTTP的协议头内容的认识
https://segmentfault.com/a/1190000016928807
2018-11-06T22:54:18+08:00
2018-11-06T22:54:18+08:00
caoweiju
https://segmentfault.com/u/caoweiju
0
<h2>http协议</h2>
<p>HTTP协议(HyperText Transfer Protocol,超文本传输协议)是因特网上应用最为广泛的一种网络传输协议,所有的WWW文件都必须遵守这个标准。</p>
<p>HTTP是一个基于TCP/IP通信协议来传递数据(HTML 文件, 图片文件, 查询结果等</p>
<h3>http报文</h3>
<ol>
<li>
<p>客户端请求 request<br>客户端发送一个HTTP请求到服务器的请求消息包括以下格式:请求行(request line)、请求头部(header)、空行和请求数据四个部分组成,下图给出了请求报文的一般格式。</p>
<ul><li>
<p>格式<br><img src="/img/bVbisPW?w=300&h=106" alt="图片描述" title="图片描述"></p>
<pre><code>GET /hello.txt HTTP/1.1
User-Agent: curl/7.16.3 libcurl/7.16.3 OpenSSL/0.9.7l zlib/1.2.3
Host: www.example.com
Accept-Language: en, mi</code></pre>
</li></ul>
</li>
<li>
<p>服务端响应 response<br>HTTP响应也由四个部分组成,分别是:状态行、消息报头、空行和响应正文。</p>
<ul><li>
<p>格式<br><img src="/img/bVbisQg?w=300&h=133" alt="图片描述" title="图片描述"></p>
<pre><code>HTTP/1.1 200 OK
Date: Mon, 27 Jul 2009 12:28:53 GMT
Server: Apache
Last-Modified: Wed, 22 Jul 2009 19:15:56 GMT
ETag: "34aa387-d-1568eb00"
Accept-Ranges: bytes
Content-Length: 51
Vary: Accept-Encoding
Content-Type: text/plain</code></pre>
</li></ul>
</li>
</ol>
<h4>http头部</h4>
<blockquote>HTTP 消息头允许客户端和服务器通过 request和 response传递附加信息。一个请求头由名称(不区分大小写)后跟一个冒号“:”,冒号后跟具体的值(不带换行符)组成。该值前面的引导空白会被忽略。<br>自定专用消息头可通过'X-' 前缀来添加;但是这种用法被IETF在2012年6月发布的 RFC5548 中明确弃用,原因是其会在非标准字段成为标准时造成不便;其他的消息头在 IANA 注册表 中列出, 其原始内容在 RFC 4229 中定义。 此外,IANA 还维护着被提议的新HTTP 消息头注册表. <br>根据不同上下文,可将消息头分为: <br>一般头: 同时适用于请求和响应消息,但与最终消息主体中传输的数据无关的消息头。<br>请求头: 包含更多有关要获取的资源或客户端本身信息的消息头。<br>响应头: 包含有关响应的补充信息,如其位置或服务器本身(名称和版本等)的消息头。<br>实体头: 包含有关实体主体的更多信息,比如主体长(Content-Length)度或其MIME类型。</blockquote>
<p>头部值如下:</p>
<ul>
<li>Accept<br>告诉WEB服务器自己接受什么介质类型,<em>/</em> 表示任何类型,type/* 表示该类型下的所有子类型,type/sub-type。</li>
<li>Accept-Charset<br>浏览器申明自己接收的字符集</li>
<li>Accept-Encoding<br>浏览器申明自己接收的编码方法,通常指定压缩方法,是否支持压缩,支持什么压缩方法(gzip,deflate)</li>
<li>Accept-Language<br>浏览器申明自己接收的语言</li>
</ul>
<p><em>语言跟字符集的区别:中文是语言,中文有多种字符集,比如big5,gb2312,gbk等等。</em></p>
<ul>
<li>Accept-Ranges<br>WEB服务器表明自己是否接受获取其某个实体的一部分(比如文件的一部分)的请求。bytes:表示接受,none:表示不接受。</li>
<li>Access-Control-Allow-Credentials</li>
<li>Access-Control-Allow-Headers</li>
<li>Access-Control-Allow-Methods</li>
<li>Access-Control-Allow-Origin</li>
<li>Access-Control-Expose-Headers</li>
<li>Access-Control-Max-Age</li>
<li>Access-Control-Request-Headers</li>
<li>Access-Control-Request-Method</li>
<li>Age</li>
<li>Allow</li>
<li>Alt-Svc [我来译!]</li>
<li>Authorization</li>
<li>Cache-Control</li>
<li>Clear-Site-Data</li>
<li>Connection</li>
<li>Content-Disposition</li>
<li>Content-Encoding</li>
<li>Content-Language</li>
<li>Content-Length</li>
<li>Content-Location</li>
<li>Content-Range</li>
<li>Content-Security-Policy</li>
<li>Content-Security-Policy-Report-Only</li>
<li>Content-Type</li>
<li>Cookie</li>
<li>Cookie2</li>
<li>DNT</li>
<li>Date</li>
<li>ETag</li>
<li>Early-Data [我来译!]</li>
<li>Expect</li>
<li>Expect-CT</li>
<li>Expires</li>
<li>Feature-Policy [我来译!]</li>
<li>Forwarded</li>
<li>From</li>
<li>Host</li>
<li>If-Match</li>
<li>If-Modified-Since</li>
<li>If-None-Match</li>
<li>If-Range</li>
<li>If-Unmodified-Since</li>
<li>Index [我来译!]</li>
<li>Keep-Alive</li>
<li>Large-Allocation</li>
<li>Last-Modified</li>
<li>Location</li>
<li>Origin</li>
<li>Pragma</li>
<li>Proxy-Authenticate</li>
<li>Proxy-Authorization</li>
<li>Public-Key-Pins</li>
<li>Public-Key-Pins-Report-Only</li>
<li>Range</li>
<li>Referer</li>
<li>Referrer-Policy</li>
<li>Retry-After</li>
<li>Sec-WebSocket-Accept [我来译!]</li>
<li>Server</li>
<li>Server-Timing [我来译!]</li>
<li>Set-Cookie</li>
<li>Set-Cookie2</li>
<li>SourceMap</li>
<li>HTTP Strict Transport Security</li>
<li>TE</li>
<li>Timing-Allow-Origin</li>
<li>Tk</li>
<li>Trailer</li>
<li>Transfer-Encoding</li>
<li>Upgrade-Insecure-Requests</li>
<li>User-Agent</li>
<li>Vary</li>
<li>Via</li>
<li>WWW-Authenticate</li>
<li>Warning</li>
<li>X-Content-Type-Options</li>
<li>DNS 预读取</li>
<li>X-Forwarded-For</li>
<li>X-Forwarded-Host</li>
<li>X-Forwarded-Proto</li>
<li>X-Frame-Options 响应头</li>
<li>X-XSS-Protection</li>
</ul>
<p><a href="https://link.segmentfault.com/?enc=j9OhNFqnVredjzNiUxGN3w%3D%3D.SZulM5bNuOWVDxKyQOTFyl2WyV15qEXQMwELIIOxZUhb5rKOZtXR6b21PszdDguP" rel="nofollow">https://www.jianshu.com/p/6e8...</a><br><a href="https://link.segmentfault.com/?enc=2COfZysYas3l7zJAn03g0Q%3D%3D.7LPjjaJuro7ekyB%2FEB58w7UVc8iItZ1881lseIgka2ca8cUWZDDPv2Hn%2F%2B5IXB4AUHqI%2BuBwuOmSMzLDc2CxNQ%3D%3D" rel="nofollow">https://www.cnblogs.com/s3131...</a></p>
Linux的一下常用命令详解
https://segmentfault.com/a/1190000016629143
2018-10-09T23:15:03+08:00
2018-10-09T23:15:03+08:00
caoweiju
https://segmentfault.com/u/caoweiju
0
<h2>对于lunix系统而言</h2>
<p>Linux是一套免费使用和自由传播的类Unix操作系统,是一个基于POSIX和UNIX的多用户、多任务、支持多线程和多CPU的操作系统。它能运行主要的UNIX工具软件、应用程序和网络协议。它支持32位和64位硬件。Linux继承了Unix以网络为核心的设计思想,是一个性能稳定的多用户网络操作系统。</p>
<p>目前大部分服务器都是Linux系统,开发人员必不可少的也会使用linux:</p>
<ul>
<li>稳定、安全</li>
<li>自由开放</li>
<li>简洁</li>
<li>开发友好</li>
</ul>
<h3>lunix指令</h3>
<p>想要很好的高效使用linux,那么命令将会是不得不学习的部分,有时候使用命令会比编程来的更加高效,也能一定程度上取代一些繁琐的操作。</p>
<p>常见的的命令很多。要全部记住估计不太靠谱,所以有一个很通用的方法,查看一个命令的使用方法;</p>
<ul>
<li>
<p>man指令 <code>man [commend]</code> 查看一个命令的使用方法</p>
<ul>
<li>man ls</li>
<li>man curl</li>
<li>man open</li>
</ul>
</li>
<li>
<p>--help: <code>[commend] --help</code> 查看部分指令帮助说明【并不适用全部命令】</p>
<ul><li>curl --help</li></ul>
</li>
</ul>
<h4>通用型命令</h4>
<ul>
<li>
<p>ls命令用于显示指定工作目录下之内容(列出目前工作目录所含之文件及子目录)。</p>
<blockquote>语法: <code>ls [-alrtAFR] [name...]</code><br>参数 :<br>-a 显示所有文件及目录 (ls内定将文件名或目录名称开头为"."的视为隐藏档,不会列出)<br>-l 除文件名称外,亦将文件型态、权限、拥有者、文件大小等资讯详细列出<br>-r 将文件以相反次序显示(原定依英文字母次序)<br>-t 将文件依建立时间之先后次序列出<br>-A 同 -a ,但不列出 "." (目前目录) 及 ".." (父目录)<br>-F 在列出的文件名称后加一符号;例如可执行档则加 "*", 目录则加 "/"<br>-R 若目录下有文件,则以下之文件亦皆依序列出</blockquote>
</li>
<li>
<p>Linux mkdir命令用于建立名称为 dirName 之子目录。</p>
<blockquote>语法: <code>mkdir [-p] dirName</code><br>参数说明:<br>-p 确保目录名称存在,不存在的就建一个。</blockquote>
</li>
<li>
<p>cd 切换目录</p>
<blockquote>语法: <code>cd [dirName]</code><br>参数说明:<br>dirName:要切换的目标目录。</blockquote>
</li>
<li>
<p>Linux touch命令用于修改文件或者目录的时间属性,包括存取时间和更改时间。若文件不存在,系统会建立一个新的文件。</p>
<blockquote>语法<br><code>touch [-acfm][-d<日期时间>][-r<参考文件或目录>] [-t<日期时间>][--help][--version][文件或目录…]</code><br>参数说明:<br>a 改变档案的读取时间记录。<br>m 改变档案的修改时间记录。<br>c 假如目的档案不存在,不会建立新的档案。与 --no-create 的效果一样。<br>f 不使用,是为了与其他 unix 系统的相容性而保留。<br>r 使用参考档的时间记录,与 --file 的效果一样。<br>d 设定时间与日期,可以使用各种不同的格式。<br>t 设定档案的时间记录,格式与 date 指令相同。<br>--no-create 不会建立新档案。<br>--help 列出指令格式。<br>--version 列出版本讯息。</blockquote>
</li>
<li>echo 创建带有内容的文件</li>
<li>
<p>cat 查看文件内容<br> 语法: <code>cat [-benstuv] [file ...]</code></p>
<blockquote>参数说明:<br> -b Number the non-blank output lines, starting at 1.<br> -e Display non-printing characters (see the -v option), and display a dollar sign (`$') at the end of each line.<br> -n Number the output lines, starting at 1.<br> -s Squeeze multiple adjacent empty lines, causing the output to be single spaced.<br> -t Display non-printing characters (see the -v option), and display tab characters as `^I'.<br> -u Disable output buffering.<br> -v Display non-printing characters so they are visible. Control characters print as <code>^X' for control-X; the delete character (octal 0177) prints as </code>^?'. Non-ASCII char-acters (with the high bit set) are printed as `M-' (for meta) followed by the character for the low 7 bits.</blockquote>
</li>
<li>
<p>cp 拷贝</p>
<blockquote>语法: <code>cp [options] source dest</code> 或 <code>cp [options] source... directory</code><br>参数说明:<br>-a:此选项通常在复制目录时使用,它保留链接、文件属性,并复制目录下的所有内容。其作用等于dpR参数组合。<br>-d:复制时保留链接。这里所说的链接相当于Windows系统中的快捷方式。<br>-f:覆盖已经存在的目标文件而不给出提示。<br>-i:与-f选项相反,在覆盖目标文件之前给出提示,要求用户确认是否覆盖,回答"y"时目标文件将被覆盖。<br>-p:除复制文件的内容外,还把修改时间和访问权限也复制到新文件中。<br>-r:若给出的源文件是一个目录文件,此时将复制该目录下所有的子目录和文件。<br>-l:不复制文件,只是生成链接文件。</blockquote>
</li>
<li>
<p>mv命令用来为文件或目录改名、或将文件或目录移入其它位置。</p>
<blockquote>语法: <code>mv [options] source dest</code> 或者 <code>mv [options] source... directory</code><br>参数说明:<br>-i: 若指定目录已有同名文件,则先询问是否覆盖旧文件;<br>-f: 在mv操作要覆盖某已有的目标文件时不给任何指示;</blockquote>
</li>
<li>
<p>rm命令用于删除一个文件或者目录。</p>
<blockquote>语法 <code>rm [options] name...</code><br>参数:<br>-i 删除前逐一询问确认。<br>-f 即使原档案属性设为唯读,亦直接删除,无需逐一确认。<br>-r 将目录及以下之档案亦逐一删除。</blockquote>
</li>
<li>find 在文件系统中搜索某文件</li>
<li>wc 统计文本中行数、字数、字符数</li>
<li>grep 在文本文件中查找某个字符串</li>
<li>rmdir 删除空目录</li>
<li>
<p>tree 树形结构显示目录,需要安装tree包</p>
<blockquote>y语法:<code>tree [-aACdDfFgilnNpqstux][-I <范本样式>][-P <范本样式>][目录...]</code><br>-a 显示所有文件和目录<br>-d 显示目录名称而非内容<br>-f 在每个文件或目录之前,显示完整的相对路径名称<br>-F 在执行文件,目录,Socket,符号连接,管道名称名称,各自加上"*","/","=","@","|"号。<br>-r 以相反次序排列<br>-t 用文件和目录的更改时间排序<br>-L n 只显示 n 层目录 (n 为数字)<br>-dirsfirst 目录显示在前,文件显示在后<br>-A 使用ASNI绘图字符显示树状图而非以ASCII字符组合。<br>-C 在文件和目录清单加上色彩,便于区分各种类型。<br>-D 列出文件或目录的更改时间。<br>-g 列出文件或目录的所属群组名称,没有对应的名称时,则显示群组识别码。<br>-i 不以阶梯状列出文件或目录名称。<br>-I 不显示符合范本样式的文件或目录名称。<br>-l 如遇到性质为符号连接的目录,直接列出该连接所指向的原始目录。<br>-n 不在文件和目录清单加上色彩。<br>-N 直接列出文件和目录名称,包括控制字符。<br>-p 列出权限标示。<br>-P 只显示符合范本样式的文件或目录名称。<br>-q 用"?"号取代控制字符,列出文件和目录名称。<br>-s 列出文件或目录大小。<br>-u 列出文件或目录的拥有者名称,没有对应的名称时,则显示用户识别码。<br>-x 将范围局限在现行的文件系统中,若指定目录下的某些子目录,其存放于另一个文件系统上,则将该子目录予以排除在寻找范围外。</blockquote>
</li>
<li>pwd 显示当前目录</li>
<li>ln 创建链接文件</li>
<li>more、less 分页显示文本文件内容</li>
<li>head、tail 显示文件头、尾内容</li>
<li>
<p>open 在终端打开文件或者软件</p>
<blockquote>Options: <br> -a Opens with the specified application.<br> -b Opens with the specified application bundle identifier.<br> -e Opens with TextEdit.<br> -t Opens with default text editor.<br> -f Reads input from standard input and opens with TextEdit.<br> -F --fresh Launches the app fresh, that is, without restoring windows. Saved persistent state is lost, excluding Untitled documents.<br> -R, --reveal Selects in the Finder instead of opening.<br> -W, --wait-apps Blocks until the used applications are closed (even if they were already running).<br> --args All remaining arguments are passed in argv to the application's main() function instead of opened.<br> -n, --new Open a new instance of the application even if one is already running.<br> -j, --hide Launches the app hidden.<br> -g, --background Does not bring the application to the foreground.<br> -h, --header Searches header file locations for headers matching the given filenames, and opens them.<br> -s For -h, the SDK to use; if supplied, only SDKs whose names contain the argument value are searched.<br> Otherwise the highest versioned SDK in each platform is used.</blockquote>
</li>
<li>curl <code>man curl</code> 查看</li>
</ul>
<h4>系统管理命令</h4>
<ul>
<li>stat 显示指定文件的详细信息,比ls更详细</li>
<li>who 显示在线登陆用户</li>
<li>whoami 显示当前操作用户</li>
<li>hostname 显示主机名</li>
<li>uname 显示系统信息</li>
<li>top 动态显示当前耗费资源最多进程信息</li>
<li>ps 命令用于显示当前进程 (process) 的状态。 ps -aux</li>
<li>du 查看目录大小 du -h --max-depth=1 --exclude=path 用户目录下带有单位显示目录信息,只显示一级,子文件内部不单独展示, 排除path文件/文件夹</li>
<li>df 查看磁盘大小 df -h 带有单位显示磁盘信息</li>
<li>ifconfig 查看网络情况</li>
<li>ping 测试网络连通</li>
<li>netstat 显示网络状态信息</li>
<li>clear 清屏</li>
<li>kill 杀死进程,可以先用ps 或 top命令查看进程的id,然后再用kill命令杀死进程。</li>
<li>
<p>lsof</p>
<blockquote>是一个列出当前系统打开文件的工具。在linux环境下,任何事物都以文件的形式存在,通过文件不仅仅可以访问常规数据,还可以访问网络连接和硬件。所以如传输控制协议 (TCP) 和用户数据报协议 (UDP) 套接字等,系统在后台都为该应用程序分配了一个文件描述符,无论这个文件的本质如何,该文件描述符为应用程序与基础操作系统之间的交互提供了通用接口。因为应用程序打开文件的描述符列表提供了大量关于这个应用程序本身的信息,因此通过lsof工具能够查看这个列表对系统监测以及排错将是很有帮助的。<br> 主要使用: <code>lsof -i [46][protocol][@hostname|hostaddr][:service|port]</code><br><code>-i</code>参数说明:</blockquote>
</li>
<li><ul>
<li>46 specifies the IP version, IPv4 or IPv6 that applies to the following address. '6' may be be specified only if the UNIX dialect supports IPv6. If neither '4' nor '6' is specified, the following address applies to all IP versions.</li>
<li>protocol is a protocol name - TCP, UDP</li>
<li>hostname is an Internet host name. Unless a specific IP version is specified, open network files associated with host names of all versions will be selected.</li>
<li>hostaddr is a numeric Internet IPv4 address in dot form; or an IPv6 numeric address in colon form, enclosed in brackets, if the UNIX dialect supports IPv6. When an IP version is selected, only its numeric addresses may be specified.</li>
</ul></li>
<ul>
<li>service is an /etc/services name - e.g., smtp - or a list of them.</li>
<li>
<p>port is a port number, or a list of them.</p>
<blockquote>实例: <br>lsof -i 4 //ipv4查询<br>lsof -i tcp // 协议查询<br>lsof -i @127.0.0.1 // 地址端口查询<br>lsof -i :80 // 端口查询</blockquote>
</li>
</ul>
</ul>
<h4>打包压缩相关命令</h4>
<ul>
<li>gzip:</li>
<li>bzip2:</li>
<li>
<p>tar: 打包压缩<br>-c 归档文件<br>-x 压缩文件<br>-z gzip压缩文件<br>-j bzip2压缩文件<br>-v 显示压缩或解压缩过程 v(view)<br>-f 使用档名</p>
<blockquote>例:<br>tar -cvf /home/abc.tar /home/abc 只打包,不压缩<br>tar -zcvf /home/abc.tar.gz /home/abc 打包,并用gzip压缩<br>tar -jcvf /home/abc.tar.bz2 /home/abc 打包,并用bzip2压缩<br>当然,如果想解压缩,就直接替换上面的命令tar -cvf / tar -zcvf / tar -jcvf 中的“c” 换成“x” 就可以了。</blockquote>
</li>
</ul>
<h4>关机/重启机器</h4>
<ul>
<li>shutdown<br>-r 关机重启<br>-h 关机不重启</li>
<li>now 立刻关机</li>
<li>halt 关机</li>
<li>reboot 重启</li>
</ul>