浏览器如何加载网页 — JavaScript PerformanceTiming

在地址栏中输入一个 url,发生了哪些事情?

  1. 输入 blog.zhengxianjun.com
  2. 浏览器查找域名的 IP 地址
    1. 查找浏览器 hosts 缓存
    2. 查找系统缓存——本机 hosts 文件
    3. 查找最近的本地域名服务器(LDNS)
    4. (LDNS)查找 Root Server->返回所在域的 gTLD Server(全球共13台国际顶级域名服务器)->查找域名对应的 Name Server->匹配域名和 IP 映射表->返回IP记录以及 TTL->LDNS 缓存并返回给浏览器
  3. 浏览器向服务器发起一个 HTTP 请求报文
    1. 应用层协议 HTTP 通过TCP报文发送到服务器
    2. TCP 3次握手(HTTP 1.0 规定服务器处理完成后立即断开TCP连接,1.1 版本)
    3. 返回 HTTP 报文,如果包含重定向信息,浏览器进行重定向(重定向次数限制)
  4. 服务器处理请求,并返回 HTTP 响应报文
  5. 浏览器接收 HTML,分析 HTML 中的资源(图片、样式、音视频),继续请求
  6. 浏览器呈现网页

JavaScript 提供的 PerformanceTiming 接口详述了各个阶段发生的时间点。

PerformanceTiming 定义

PerformanceTiming 所有属性均为只读。

PerformanceTiming 示例

网页加载时间示例

w3 文档地址:http://www.w3.org/TR/navigation-timing/

JavaScript RSA 非对称加密

使用 JSEncrypt 完成 JavaScript 非对称加密。

假定整个加解密过程中使用的密钥如下。

公钥:

-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC5A/TPEmOQYgT2po11qvjeBUPE
dqUEz1Z7MeHH7KI2p74pYK8RsvYngy1cH/wnMXmsf+Wb3tmlqNGa7atW8wlpSfXX
QV9bFECPEVRnESo8xtN7ZAlJFcdRvBVgfVwC3m9HWpVvKnd9NREXIcg5NHh57q7u
lsGCZJ2VOJm9EIgFEwIDAQAB
-----END PUBLIC KEY-----

私钥:

-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQC5A/TPEmOQYgT2po11qvjeBUPEdqUEz1Z7MeHH7KI2p74pYK8R
svYngy1cH/wnMXmsf+Wb3tmlqNGa7atW8wlpSfXXQV9bFECPEVRnESo8xtN7ZAlJ
FcdRvBVgfVwC3m9HWpVvKnd9NREXIcg5NHh57q7ulsGCZJ2VOJm9EIgFEwIDAQAB
AoGBALcfBVVXHBiyC7udSfInET+e8l4oGFjUZwJ0csaQnlV+XadSvLTF7wFYwrKm
LcsVGxrzU+2c+ssOdrfjeW0MDEjrbd1xtmayP8Kh2/Pg+9jZqj188tTlLwzUW6iz
KDEpiG5P1f1cbKY+R/BHQIKt7vcd2QMNVctxSkjl1uSvU/ERAkEA7uCuAJsVgmui
NjDscoXyj+QRFWqDnUNCZqSqjYw7/BC36xYg/Xolw/bqg9aTgua96fv9k9hExOBY
eNV3mj63bwJBAMZG7J5/vc3bkVwOS3A5E8j4hwCIFDylbKQ8chdulC3wwDLaSRdE
evUfhAmMev1cc4QiVaXzGKPcS9ko8Gdz2p0CQAftfvjYLMOSTOTdhMtcNKuf1w1N
5qZOeCKt7lcaQ1dfOqtbpaaj6iLxy+CqO2UJwV3FlinU8JtUEruX4gtFb5MCQGgb
l2RFuHhdgH5wdwXOwme0rtYFnXKWfWvi3RkWk7FnhtNssBIKf/EzAhYtb+qWX4US
rhv7f4WSRzUX/NqlBzUCQQCfDpC5/DZ/7RMKbDj7inW2G/3T56jzCdicIAgN0erZ
jcbB7+8VQLjcw5LFYPwgjjz5v6Amw42VY+dBUNWVEH9C
-----END RSA PRIVATE KEY-----

JSEncrypt 使用私钥加密示例:

// 创建 RSA 对象
var crypt = new JSEncrypt();

// 私钥
var private_key = "-----BEGIN RSA PRIVATE KEY-----...";

crypt.setPrivateKey(private_key);

var encrypted = crypt.encrypt('123456');

得到结果:

bC8nemetJfmenSldUccrHcY+aMVBO1ANYJky42vKhv+8iMmecAmDSalOj/065+AZBRhsWuT0C26A5IJTnI9COpA3L1xV54Mwz8j3Y0DdGRqaAFH+lkibVj/JOsTYfKVWnPMwc0D/EL2IJdi18sct2s3CvGxp7+1sRayKSoPvTa8=

RSA 加密得到的密文每次都不一样, 因为加入了随机数。

JSEncrypt 使用公钥解密示例:

var crypt = new JSEncrypt();
var private_key = "-----BEGIN RSA PRIVATE KEY-----...";

crypt.setPrivateKey(private_key);

var decrypted = crypt.decrypt('123456');

PHP 使用私钥加密示例:

openssl_pkey_new(array('private_key_bits' => 1024));

PHP 使用公钥加密示例:

openssl_pkey_new(array('private_key_bits' => 1024));

JSEncrypt 同时支持自动创建公钥和私钥:

// 支持 512、1024、2048、4096
// key 越长, 生成密钥和加密时间越长
var crypt = new JSEncrypt({default_key_size: 1024});

// 获取公钥
var public_key = crypt.getPublicKey();

// 获取私钥
var private_key = crypt.getPrivateKey();

利用 JSEncrypt 可以完成在前端网页对密码等敏感信息进行加密,传输到服务器端再进行解密。

JSEncrypt 项目地址:https://github.com/travist/jsencrypt

在 JSEncrypt 基础上实现的在线工具 —— RSA 加密解密

JavaScript 箭头函数 —— Arrow Function

Arrow Function 是 ECMAScript6 中的新特性。

先看两个酷炫的箭头函数示例:

var a1 = [
	"Hydrogen",
	"Helium",
	"Lithium",
	"Beryl­lium"
];

var a2 = a1.map(function(i){ return i.length });

var a3 = a1.map( i => i.length );

更炫

var b1 = [4, 3, 2, 1];

var b2 = b1.sort(function(i, j){ return i > j });

var b3 = b1.sort((i, j) => i > j);

在最新版的 Firefox 中可以体验这种特性。

Arrow Function map

Arrow Function sort

使用循环实现斐波那契数列

递归中比较常见的例子是斐波那契数列、汉诺塔。

使用递归实现斐波那契数列其实很浪费,f(n) = f(n-1) + f(n-2)。在进一步计算 f(n-1) = f(n-2) + f(n-3),会发现 f(n-2) 被重复计算。

下面是通过循环实现的斐波那契数列:

function Fibonacci(number) {
	var i, list = new Array();

	list[0] = 0;
	list[1] = 1;

	for (i = 1; i < number; i++) {
		list[i + 1] = list[i] + list[i - 1];
	}

	return list[number];
}

获取完整的斐波那契数列:

function Fibonacci(number, full) {
	var i, list = new Array();

	list[0] = 0;
	list[1] = 1;

	for (i = 1; i < number; i++) {
		list[i + 1] = list[i] + list[i - 1];
	}

	if (full) {
		return list;
	}

	return list[number];
}

JavaScript Crypto-JS 使用手册

使用 Crypto-JS 可以非常方便地在 JavaScript 进行 MD5、SHA1、SHA2、SHA3、RIPEMD-160 哈希散列,进行 AES、DES、Rabbit、RC4、Triple DES 加解密。

基于 Crypto-JS 实现的在线加密解密工具 —— 在线哈希、在线散列 和 在线加密、在线解密

下面讲述如何使用 Crypto-JS。

Crypto-JS 源码托管在 Google Code,当前版本是 3.1。因为一般在国内也无法打开,所以把源代码分享到百度盘:http://pan.baidu.com/s/1bnyIGxT

Crypto-JS 原网址是 https://code.google.com/p/crypto-js/文中的英文描述均是原作者所有,Crypto-JS 采用的授权协议跟 MIT 类似,可以在任何场景放心使用。

文章最末附上 Crypto-JS 文件目录结构。

使用 Crypto-JS 进行哈希、散列

  • md5

引入 md5.js

<script src="cryptojs/rollups/md5.js"></script>

调用 md5 方法

var str = '123456';
CryptoJS.MD5(str);
  • pbkdf2

PBKDF2 is a password-based key derivation function. In many applications of cryptography, user security is ultimately dependent on a password, and because a password usually can’t be used directly as a cryptographic key, some processing is required.

A salt provides a large set of keys for any given password, and an iteration count increases the cost of producing keys from a password, thereby also increasing the difficulty of attack.

引入 pbkdf2.js

<script src="cryptojs/rollups/pbkdf2.js"></script>

调用 pbkdf2 方法

// 官方示例
var str = '123456';
var salt = CryptoJS.lib.WordArray.random(128/8);

var key128Bits = CryptoJS.PBKDF2(str, salt, { keySize: 128/32 });
var key256Bits = CryptoJS.PBKDF2(str, salt, { keySize: 256/32 });
var key512Bits = CryptoJS.PBKDF2(str, salt, { keySize: 512/32 });

var key512Bits1000Iterations = CryptoJS.PBKDF2("Secret Passphrase", salt, {
keySize: 512/32,
iterations: 1000
});
  • ripemd160

引入 ripemd160.js

<script src="cryptojs/rollups/ripemd160.js"></script>

调用 ripemd160 方法

var str = '123456';
CryptoJS.RIPEMD160(str);
  • sha 系列:sha1、sha2、sha3…

sha 具有一系列散列算法

The SHA hash functions were designed by the National Security Agency (NSA). SHA-1 is the most established of the existing SHA hash functions, and it’s used in a variety of security applications and protocols. Though, SHA-1’s collision resistance has been weakening as new attacks are discovered or improved.

SHA-256 is one of the four variants in the SHA-2 set. It isn’t as widely used as SHA-1, though it appears to provide much better security.

SHA-512 is largely identical to SHA-256 but operates on 64-bit words rather than 32.
CryptoJS also supports SHA-224 and SHA-384, which are largely identical but truncated versions of SHA-256 and SHA-512 respectively.

SHA-3 is the winner of a five-year competition to select a new cryptographic hash algorithm where 64 competing designs were evaluated.
SHA-3 can be configured to output hash lengths of one of 224, 256, 384, or 512 bits. The default is 512 bits.

引入 sha 相关 js

<script src="cryptojs/rollups/sha1.js"></script>
<script src="cryptojs/rollups/sha3.js"></script>
<script src="cryptojs/rollups/sha224.js"></script>
<script src="cryptojs/rollups/sha256.js"></script>
<script src="cryptojs/rollups/sha384.js"></script>
<script src="cryptojs/rollups/sha512.js"></script>

调用 sha 相关方法

var str = '123456';
CryptoJS.SHA1(str);

var str = '123456';
CryptoJS.SHA3(str);

// 配置输出的哈希长度
CryptoJS.SHA3(str, {outputLength : 224});
CryptoJS.SHA3(str, {outputLength : 256});
CryptoJS.SHA3(str, {outputLength : 384});
CryptoJS.SHA3(str, {outputLength : 512});

var str = '123456';
CryptoJS.SHA224(str);

var str = '123456';
CryptoJS.SHA256(str);

var str = '123456';
CryptoJS.SHA284(str);

var str = '123456';
CryptoJS.SHA512(str);
  • hmac 系列:hmac_md5、hmac_ripemd160、hmac_sha1、hmac_sha3…

引入 hmac 相关 js

<script src="cryptojs/rollups/hmac-sha1.js">
</script>
<script src="cryptojs/rollups/hmac-sha3.js">
</script>
<script src="cryptojs/rollups/hmac-sha224.js">
</script>
<script src="cryptojs/rollups/hmac-sha256.js">
</script>
<script src="cryptojs/rollups/hmac-sha384.js">
</script>
<script src="cryptojs/rollups/hmac-sha512.js">
</script>

调用 hmac 相关 方法

var str = '123456';
var password = 'password';

// Hmac 相关调用前都增加了 Hmac
CryptoJS.HmacMD5(str, password);
CryptoJS.HmacRIPEMD160(str, password);
CryptoJS.HmacSHA1(str, password);
CryptoJS.HmacSHA3(str, password);
CryptoJS.HmacSHA224(str, password);
CryptoJS.HmacSHA256(str, password);
CryptoJS.HmacSHA384(str, password);
CryptoJS.HmacSHA512(str, password);

使用 Crypto-JS 进行加密、解密

Crypto-JS 相关 encrypt 函数会并不直接返回字符串,需要调用返回对象的 toString 方法,或者通过 Crypto-JS 转码才能得到真实的结果。

  • AES

引入 aes.js

<script src="cryptojs/rollups/aes.js"></script>

调用 CryptoJS.AES

// 官方示例, 每次输出的密文都不一样
CryptoJS.AES.encrypt("Message", "Secret Passphrase");

// 正确用法

var str = '123456';
// 密钥 16 位
var key = '0123456789abcdef';
// 初始向量 initial vector 16 位
var iv = '0123456789abcdef';
// key 和 iv 可以一致

key = CryptoJS.enc.Utf8.parse(key);
iv = CryptoJS.enc.Utf8.parse(iv);

var encrypted = CryptoJS.AES.encrypt(str, key, {
	iv: iv,
	mode: CryptoJS.mode.CBC,
	padding: CryptoJS.pad.Pkcs7
});

// 转换为字符串
encrypted = encrypted.toString();

// mode 支持 CBC、CFB、CTR、ECB、OFB, 默认 CBC
// padding 支持 Pkcs7、AnsiX923、Iso10126
// 、NoPadding、ZeroPadding, 默认 Pkcs7, 即 Pkcs5

var decrypted = CryptoJS.AES.decrypt(encrypted, key, {
	iv: iv,
	mode: CryptoJS.mode.CBC,
	padding: CryptoJS.pad.Pkcs7
});

// 转换为 utf8 字符串
decrypted = CryptoJS.enc.Utf8.stringify(decrypted);

// 引入其他加密模式, 填充模式需要引入对应的 js 文件
/*
cryptojs/components/mode-cfb-min.js
cryptojs/components/mode-ctr-min.js
cryptojs/components/mode-ecb-min.js
cryptojs/components/mode-ofb-min.js
cryptojs/components/pad-ansix923-min.js
cryptojs/components/pad-iso10126-min.js
cryptojs/components/pad-iso97971-min.js
cryptojs/components/pad-nopadding-min.js
*/
  • DES、Triple DES

DES、Triple DES 的调用形式与 AES 一致。

引入 triple.js, DES 和 Triple DES 都定义在 tripledes.js

<script src="cryptojs/rollups/tripledes.js"></script>

调用 CryptoJS.DES, CryptoJS.TripleDES

var str = '123456';
var key = '0123456789abcdef';
var iv = '0123456789abcdef';

key = CryptoJS.enc.Utf8.parse(key);
iv = CryptoJS.enc.Utf8.parse(iv);

// DES 加密
var encrypted = CryptoJS.DES.encrypt(str, key, {
	iv: iv,
	mode: CryptoJS.mode.CBC,
	padding: CryptoJS.pad.Pkcs7
});

// 转换为字符串
encrypted = encrypted.toString();

// DES 解密
var decrypted = CryptoJS.DES.decrypt(encrypted, key, {
	iv: iv,
	mode: CryptoJS.mode.CBC,
	padding: CryptoJS.pad.Pkcs7
});

// 转换为 utf8 字符串
decrypted = CryptoJS.enc.Utf8.stringify(decrypted);

// Triple DES 加密
var encrypted = CryptoJS.TripleDES.encrypt(str, key, {
	iv: iv,
	mode: CryptoJS.mode.CBC,
	padding: CryptoJS.pad.Pkcs7
});

// 转换为字符串
encrypted = encrypted.toString();

// Triple DES 解密
var decrypted = CryptoJS.TripleDES.decrypt(encrypted, key, {
	iv: iv,
	mode: CryptoJS.mode.CBC,
	padding: CryptoJS.pad.Pkcs7
});

// 转换为 utf8 字符串
decrypted = CryptoJS.enc.Utf8.stringify(decrypted);
  • Rabbit、RC4

Rabbit、RC4 调用方式一致,不支持 mode、padding。

引入 rabbit.js

<script src="cryptojs/rollups/rabbit.js"></script>

调用 CryptoJS.Rabbit

var str = '123456';
var key = '0123456789abcdef';
var iv = '0123456789abcdef';

key = CryptoJS.enc.Utf8.parse(key);
iv = CryptoJS.enc.Utf8.parse(iv);

var encrypted = CryptoJS.Rabbit.encrypt(str, key, {
	iv: iv
});

// 转换为字符串
encrypted = encrypted.toString();

var decrypted = CryptoJS.Rabbit.decrypt(encrypted, key, {
	iv: iv
});

// 转换为 utf8 字符串
decrypted = CryptoJS.enc.Utf8.stringify(decrypted);

引入 rc4.js

<script src="cryptojs/rollups/rc4.js"></script>

调用 CryptoJS.RC4

var str = '123456';
var key = '0123456789abcdef';
var iv = '0123456789abcdef';

key = CryptoJS.enc.Utf8.parse(key);
iv = CryptoJS.enc.Utf8.parse(iv);

var encrypted = CryptoJS.RC4.encrypt(str, key, {
	iv: iv
});

// 转换为字符串
encrypted = encrypted.toString();

var decrypted = CryptoJS.RC4.decrypt(encrypted, key, {
	iv: iv
});

// 转换为 utf8 字符串
decrypted = CryptoJS.enc.Utf8.stringify(decrypted);

Crypto-JS 文件目录结构

  • cryptojs
    • components
      • aes.js
      • cipher-core.js
      • core.js
      • enc-base64.js
      • enc-utf16.js
      • evpkdf.js
      • format-hex.js
      • hmac.js
      • lib-typedarrays.js
      • md5.js
      • mode-cfb.js
      • mode-ctr.js
      • mode-ctr-gladman.js
      • mode-ecb.js
      • mode-ofb.js
      • pad-ansix923.js
      • pad-iso10126.js
      • pad-iso97971.js
      • pad-nopadding.js
      • pad-zeropadding.js
      • pbkdf2.js
      • rabbit.js
      • rabbit-legacy.js
      • rc4.js
      • ripemd160.js
      • sha1.js
      • sha3.js
      • sha224.js
      • sha256.js
      • sha384.js
      • sha512.js
      • tripledes.js
      • x64-core.js
    • rollups
      • aes.js
      • hmac-md5.js
      • hmac-ripemd160.js
      • hmac-sha1.js
      • hmac-sha3.js
      • hmac-sha224.js
      • hmac-sha256.js
      • hmac-sha384.js
      • hmac-sha512.js
      • md5.js
      • pbkdf2.js
      • rabbit.js
      • rabbit-legacy.js
      • rc4.js
      • ripemd160.js
      • sha1.js
      • sha3.js
      • sha224.js
      • sha256.js
      • sha384.js
      • sha512.js
      • tripledes.js

cryptojs/components 目录下的所有文件都会对应一个压缩文件,比如 cryptojs/components/aes.js 同时会有一个 cryptojs/components/aes-min.js 文件。

cryptojs/rollups 目录下的所有文件都已经压缩完毕,每个文件都可以单独调用。

HTML特殊符号、命名实体、十进制编码对照表

HTML特殊符号、命名实体、十进制编码对照表

特殊符号 命名实体 十进制编码 特殊符号 命名实体 十进制编码
Α &Alpha; &#913; Β &Beta; &#914;
Γ &Gamma; &#915; Δ &Delta; &#916;
Ε &Epsilon; &#917; Ζ &Zeta; &#918;
Η &Eta; &#919; Θ &Theta; &#920;
Ι &Iota; &#921; Κ &Kappa; &#922;
Λ &Lambda; &#923; Μ &Mu; &#924;
Ν &Nu; &#925; Ξ &Xi; &#926;
Ο &Omicron; &#927; Π &Pi; &#928;
Ρ &Rho; &#929; Σ &Sigma; &#931;
Τ &Tau; &#932; Υ &Upsilon; &#933;
Φ &Phi; &#934; Χ &Chi; &#935;
Ψ &Psi; &#936; Ω &Omega; &#937;
α &alpha; &#945; β &beta; &#946;
γ &gamma; &#947; δ &delta; &#948;
ε &epsilon; &#949; ζ &zeta; &#950;
η &eta; &#951; θ &theta; &#952;
ι &iota; &#953; κ &kappa; &#954;
λ &lambda; &#955; μ &mu; &#956;
ν &nu; &#957; ξ &xi; &#958;
ο &omicron; &#959; π &pi; &#960;
ρ &rho; &#961; ς &sigmaf; &#962;
σ &sigma; &#963; τ &tau; &#964;
υ &upsilon; &#965; φ &phi; &#966;
χ &chi; &#967; ψ &psi; &#968;
ω &omega; &#969; ϑ &thetasym; &#977;
ϒ &upsih; &#978; ϖ &piv; &#982;
&bull; &#8226; &hellip; &#8230;
&prime; &#8242; &Prime; &#8243;
&oline; &#8254; &frasl; &#8260;
&weierp; &#8472; &image; &#8465;
&real; &#8476; &trade; &#8482;
&alefsym; &#8501; &larr; &#8592;
&uarr; &#8593; &rarr; &#8594;
&darr; &#8595; &harr; &#8596;
&crarr; &#8629; &lArr; &#8656;
&uArr; &#8657; &rArr; &#8658;
&dArr; &#8659; &hArr; &#8660;
&forall; &#8704; &part; &#8706;
&exist; &#8707; &empty; &#8709;
&nabla; &#8711; &isin; &#8712;
&notin; &#8713; &ni; &#8715;
&prod; &#8719; &sum; &#8722;
&minus; &#8722; &lowast; &#8727;
&radic; &#8730; &prop; &#8733;
&infin; &#8734; &ang; &#8736;
&and; &#8869; &or; &#8870;
&cap; &#8745; &cup; &#8746;
&int; &#8747; &there4; &#8756;
&sim; &#8764; &cong; &#8773;
&asymp; &#8773; &ne; &#8800;
&equiv; &#8801; &le; &#8804;
&ge; &#8805; &sub; &#8834;
&sup; &#8835; &nsub; &#8836;
&sube; &#8838; &supe; &#8839;
&oplus; &#8853; &otimes; &#8855;
&perp; &#8869; &sdot; &#8901;
&lceil; &#8968; &rceil; &#8969;
&lfloor; &#8970; &rfloor; &#8971;
&loz; &#9674; &spades; &#9824;
&clubs; &#9827; &hearts; &#9829;
&diams; &#9830; &nbsp; &#160;
¡ &iexcl; &#161; ¢ &cent; &#162;
£ &pound; &#163; ¤ &curren; &#164;
¥ &yen; &#165; ¦ &brvbar; &#166;
§ &sect; &#167; ¨ &uml; &#168;
© &copy; &#169; ª &ordf; &#170;
« &laquo; &#171; ¬ &not; &#172;
­ &shy; &#173; ® &reg; &#174;
¯ &macr; &#175; ° &deg; d&#176;
± &plusmn; &#177; ² &sup2; &#178;
³ &sup3; &#179; ´ &acute; &#180;
µ &micro; &#181;

JavaScript Math

JavaScript Math 是 JavaScript 内置(built-in)的一个对象,包含常用的数学常量及数学方法。

JavaScript Math

Math 对象详细介绍 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math

Math 有8个常量,接近18个数学方法,并有多个新增方法。

Math 常量

Math.E 欧拉常数 2.718281828459045
Math.LN2 2的自然对数 0.6931471805599453
Math.LN10 10的自然对数 2.302585092994046
Math.LOG2E 以10为底E的对数 1.4426950408889634
Math.LOG10E 以2为底E的对数 0.4342944819032518
Math.PI 圆周率 3.141592653589793
Math.SQRT1_2 1/2的平方根 0.7071067811865476
Math.SQRT2 2的平方根 1.4142135623730951

Math 方法

Math.abs(x) 获取 x 的绝对值
Math.acos(x) 获取 x 的反余弦值
Math.acosh(x) 获取 x 的反双曲余弦值 实验方法
Math.asin(x) 获取 x 的反正弦值
Math.asinh(x) 获取 x 的反双曲正弦值 实验方法
Math.atan(x) 以介于 -PI/2 与 PI/2 弧度之间的数值来获取 x 的反正切值
Math.atanh(x) 获取 x 的反双曲正切值 实验方法
Math.atan2(x, y) 获取 y/x 的反正切值
Math.cbrt(x) 获取 x 的立方根 实验方法
Math.ceil(x) 获取大于等于 x 的最小整数
Math.cos(x) 获取 x 的余弦值
Math.cosh(x) 获取 x 的双曲余弦值 实验方法
Math.exp(x) 获取 Ex, Math.E 的 x 次幂
Math.expm1(x) 获取 Math.exp(x)-1 的值 实验方法
Math.floor(x) 获取小于等于 x 的最大整数
Math.fround(x) 获取与 x 最相近的单精度浮点数 实验方法
Math.hypot([x[,y[,…]]]) 获取所有参数的平方和的平方根, 统计 实验方法
Math.imul(x) 获取一个32位整数的乘积 ? 实验方法
Math.log(x) 获取以 Math.E 为底数, x 为指数的对数, 自然对数
Math.log1p(x) 获取 1 + x 的自然对数 实验方法
Math.log10(x) 获取以 10 为底数, x 为指数的对数 实验方法
Math.log2(x) 获取以 2 为底数, x 为指数的对数 实验方法
Math.max([x[,y[,…]]]) 获取所有参数中的最大值
Math.min([x[,y[,…]]]) 获取所有参数中的最小值
Math.pow(x,y) 获取 x 的 y 次幂
Math.random() 获取 0 到 1 之间的伪随机数
Math.round(x) 获取 x 四舍五入后的整数
Math.sign(x) 获取 x 的标记, 判定 x 是正数, 负数还是 0 -1, 0, 1
Math.sin(x) 获取 x 的正弦值
Math.sinh(x) 获取 x 的双曲正弦值 实验方法
Math.sqrt(x) 获取 x 的平方根
Math.tan(x) 获取 x 的正切值
Math.trunc(x) 获取 x 的整数部分,去除小数 实验方法

从 Math 常量可以看出 JavaScript 浮点数最多表示多少位。下面这段代码比较有趣:

1.1 + 2.2 // == 3.3 ?
// 得到结果 3.3000000000000003
Math.fround(1.1 + 2.2) == 3.299999952316284
// ? 得到最接近的浮点数

使用七牛CDN对博客静态资源进行加速

WordPress 博客程序默认静态资源全部存放在 wp-content、wp-includes 目录下,包括主题样式和各种插件样式。

使用七牛CDN对博客静态资源进行加速步骤:

第一步、同步所有静态资源到七牛空间

第二步、替换静态资源域名

if (!is_admin())
{
	function qiniu_ob_start()
	{
		ob_start('qiniu_cdn_replace');
	}

	function qiniu_cdn_replace($html)
	{
		if ($_SERVER['SERVER_PORT'] == '443' || $_SERVER['HTTPS'] == 'on')
		return  str_replace('blog.zhengxianjun.com/wp-content', 'dn-zhengxianjun.qbox.me/wp-content',
				str_replace('blog.zhengxianjun.com/wp-includes', 'dn-zhengxianjun.qbox.me/wp-includes', $html));

		return  str_replace('blog.zhengxianjun.com/wp-content', 'zhengxianjun.qiniudn.com/wp-content',
				str_replace('blog.zhengxianjun.com/wp-includes', 'zhengxianjun.qiniudn.com/wp-includes', $html));
	}

	add_action('wp_loaded', 'qiniu_ob_start');
}

上述代码需要添加到 wp-content/themes/twentyfifteen/functions.php。其中,twentyfifteen 是当前博客使用的主题。

实现效果

访问博客首页

博客首页

查看网络资源

网络资源

可以看到博客已经使用了CDN对静态资源加速。

以后每次更新静态资源时需要同时更新到七牛空间。

为了简化静态资源同步,使用脚本 wp-static-sync.php 同步静态资源到本地七牛空间目录,七牛的 QRSBox 会自动更新目录下的所有文件。

<?php
// 文件 wp-static-sync.php
if (!isset($_SERVER['argv']))
{
	return;
}

function copy_static($static_source, $static_target)
{
	if (!is_dir($static_source))
	{
		echo "static_source : <$static_source> is not a dir\n";
		return false;
	}

	if (!is_dir($static_target))
	{
		if (false === mkdir($static_target))
		{
			echo "mkdir ERROR target <$static_target>\n";
			return false;
		}
		else
		{
			echo "mkdir Ok target <$static_target>\n";
		}
	}

	$handler_source = opendir($static_source);
	$handler_target = opendir($static_target);

	$reg_static = '/\.css$|\.js$|\.gif$|\.jpg$|\.png$/i';

	while ($name = readdir($handler_source))
	{
		if ($name == '.' || $name == '..') continue;

		$file_source = $static_source . '/' . $name;

		if (is_file($file_source))
		{
			if (preg_match($reg_static, $name))
			{
				$file_target = $static_target . '/' . $name;
				if (false === copy($file_source, $file_target))
				{
					echo "copy ERROR <$file_source> to <$file_target>\n";
				}
				else
				{
					echo "copy Ok <$file_source> to <$file_target>\n";
				}
			}
		}
		else if (is_dir($file_source))
		{
			$file_target = $static_target . '/' . $name;
			if (false === copy_static($file_source, $file_target))
			{
				return false;
			}
			// 删除空目录
			if (count(scandir($file_target)) == 2)
			{
				if (false === rmdir($file_target))
				{
					echo "rmdir ERROR empty  <$file_target>\n";
				}
				else
				{
					echo "rmdir Ok empty  <$file_target>\n";
				}
			}
		}
	}
}

$static_source = 'D:\work\blog';
$static_target = 'D:\work\zhengxianjun_cdn\www\static';

copy_static($static_source . '/wp-content', $static_target . '/wp-content');
copy_static($static_source . '/wp-includes', $static_target . '/wp-includes');

至此,虽然流程上略长,但基本实现了想要的功能。

另一种方法,是使用 wpjam-qiniu 这款插件,该插件可以绑定到七牛空间。因为我在使用过程中出现了一些问题,之前发布的文章中图片地址出现了错误,所以使用上面所述的方法实现。

JavaScript Function bind

JavaScript bind 函数允许返回一个跟源函数一样的绑定函数。绑定函数与源函数区别在与绑定函数的 this 已经被 bind 修改。

函数定义

new Function().bind(this, arg0, arg1…)

代码示例

function sayHello(guest) {
	console.log('Hello ' + guest + ', I am ' + this.age + ' years old');
}
sayHello('Yue');

var me = {
	name: 'Seven',
	age: '24'
};

var sayHi = sayHello.bind(me);
sayHi('Yue');

执行结果

JavaScript bind

尽管没有通过调用成员方法而是直接执行函数 sayHi(‘Yue’),sayHi 内部的 this 仍然指向了对象 me,而不是默认的 window。

从控制台可以看到 sayHi 已经被“编译”为本地方法。

bind 函数的可选参数 arg0、arg1 等是绑定到源函数对应的第0个参数、第一个参数。执行绑定函数时自动传递已绑定的参数。

与 bind 相比,apply 和 call 方法是在函数执行时改变 this,bind 可以理解为在函数定义时改变 this。

apply、bind、call 对比

函数名 参数列表 说明
apply (this_arg, arguments_array) 调用函数,通过 this_arg 替代源函数默认的 this,arguments_array 是传递给函数的参数列表
var A = {
	name: 'A',
	sayHi: function(guest) {
		console.log('Hi ' + guest + ', I am ' + this.name);
	}
}
var me = {name: 'Seven'};
A.sayHi('Yue');
A.sayHi.apply(me, ['Yue']);
bind (this_arg, arg0, arg1…) 创建与源函数函数体一样的绑定函数,并根据 this_arg 和 arg0、arg1 等分别修改绑定函数的 this 和 默认参数
call (this_arg, arg0, arg1…) 调用函数,通过 this_arg 替代源函数默认的 this,arg0、arg1 等是传递给函数的参数列表
var A = {
	name: 'A',
	sayHi: function(guest) {
		console.log('Hi ' + guest + ', I am ' + this.name);
	}
}
var me = {name: 'Seven'};
A.sayHi('Yue');
A.sayHi.call(me, 'Yue');