算法
选择排序
var arr = [4,2,3,2,3,5,1,0,7,6]
Array.prototype.selectSort = function(){
for(var i=0; i<this.length; i++){
var min = i;
for(var j=i+1; j<this.length; j++){
if(this[j] < this[min]){
min = j
}
}
if(this[i] !== this[min]){
var swap = this[i];
this[i] = this[min];
this[min] = swap
}
}
}
插入排序
var arr = [4,2,3,2,3,5,1,0,7,6]
Array.prototype.insertSort = function(){
for(var i=1; i<this.length; i++){
var j = i,
temp = this[i];
while(j > 0 && this[j - 1] > temp){
this[j] = this[j - 1];
j--;
}
this[j] = temp;
}
}
正则
首尾空格:/^\s*|\s*$/g
URL:/[a-zA-Z]+:\/\/[^\s]*/
身份证:/(^\d{15}$)|(^\d{18}$)|(^\d{17}[\d|X|x]$)/
国内座机:/((^\d{3})-(\d{8})$)|(^(\d{4})-(\d{7})$)/
整理知识 HTTP 缓存
当浏览器首次对一个资源发起请求时,在不考虑其他参数的情况下,请求完成之后会将当次请求的结果缓存下来,以便下次请求更快响应。过程如下
首次发起资源请求:

浏览器再次对同一资源发起请求:

详解第一次发起请求流程:

强制缓存,此时资源只要未过期,都会触发缓存,直接对内容进行返回,如果缓存失效,则立即发起新的请求对服务器进行请求,然后将结果放入缓存中。

对比缓存:首先获取资源的标识,发送请求到服务器验证资源标志是否失效,如果未失效,则浏览器从本地获取资源,如果失效,再发起真是请求到服务器,请求新的资源内容。

强制缓存
强制缓存的关键在于如何判断缓存数据是否失效,判断的信息在 response header 信息中,主要由(Expires/Cache-control)来标明。
Expires
Expires的值为服务端返回的到期时间,即下一次请求时,请求时间小于服务端返回的到期时间,直接使用缓存数据。不过Expires 是HTTP 1.0的东西,现在默认浏览器均默认使用HTTP 1.1,所以它的作用基本忽略。
另一个问题是,到期时间是由服务端生成的,但是客户端时间可能跟服务端时间有误差,这就会导致缓存命中的误差。所以HTTP 1.1 的版本,使用Cache-Control替代。
Cache-control
Cache-Control:是最重要的规则。常见的取值有private、public、no-cache、max-age,no-store,默认为private。
private:客户端可以缓存public:客户端和代理服务器都可缓存max-age=xxx:缓存的内容将在 xxx 秒后失效no-cache:需要使用对比缓存来验证缓存数据no-store:所有内容都不会缓存,强制缓存,对比缓存都不会触发
对比缓存
对比缓存,顾名思义,需要进行比较判断是否可以使用缓存。 浏览器第一次请求数据时,服务器会将缓存标识与数据一起返回给客户端,客户端将二者备份至缓存数据库中。再次请求数据时,客户端将备份的缓存标识发送给服务器,服务器根据缓存标识进行判断,判断成功后,返回304状态码,通知客户端比较成功,可以使用缓存数据。
对于对比缓存来说,缓存标识的传递是我们着重需要理解的,它在请求header和响应header间进行传递,一共分为两种标识传递,接下来,我们分开介绍
Last-Modified / If-Modified-Since
- Last-Modified:服务器在响应请求时,告诉浏览器资源的最后修改时间。
- If-Modified-Since:再次请求服务器时,通过此字段通知服务器上次请求时,服务器返回的资源最后修改时间。服务器收到请求后发现有头 If-Modified-Since 则与被请求资源的最后修改时间进行比对。若资源的最后修改时间大于 If-Modified-Since,说明资源又被改动过,则响应整片资源内容,返回状态码200;若资源的最后修改时间小于或等于If-Modified-Since,说明资源无新修改,则响应HTTP 304,告知浏览器继续使用所保存的cache。
Etag / If-None-Match
优先级高于 Last-Modified / If-Modified-Since
- Etag:服务器响应请求时,告诉浏览器当前资源在服务器的唯一标识(生成规则由服务器决定)
- If-None-Match:再次请求服务器时,通过此字段通知服务器客户段缓存数据的唯一标识。服务器收到请求后发现有头If-None-Match 则与被请求资源的唯一标识进行比对,不同,说明资源又被改动过,则响应整片资源内容,返回状态码200;相同,说明资源无新修改,则响应HTTP 304,告知浏览器继续使用所保存的cache。
用户行为与缓存
| 用户操作 | Expires/Cache-Control | Last-Modified/Etag |
|---|---|---|
| 地址栏回车 | 有效 | 有效 |
| 页面链接跳转 | 有效 | 有效 |
| 新开窗口 | 有效 | 有效 |
| 前进、后退 | 有效 | 有效 |
| F5刷新 | 无效(BR重置max-age=0) | 有效 |
| ctrl + F5刷新 | 无效(重置CC=no-cache) | 无效(请求头丢弃该选项) |
小程序打包自动替换环境
小程序开发过程中需要对应不同的测试环境,发布线上的时候总是手动替换环境,容易忘记替换环境,如果测试环节有疏忽就容易导致线上小程序连接的是测试环境,已经有过故障是关于这方面。总结起来又三方面问题:
- 上线环境切换手动容易忘记
- 没有自动化 merge_master 的流程,容易丢失代码
- 上线之后代码没有自动 merge 到 master,导致下次提交代码丢失
对应三方面的问题目前是想将发布环境自动化,思路是首先 check 有没有 merge master,如果没有则报错,然后将配置替换成线上配置,压缩打包,生成 ratg,并将代码 merge 到 master。下面是流程脚本的实现。
const fs = require('fs');
const path = require('path');
const childProcess = require('child_process');
const spawn = childProcess.spawn;
const envReg = new RegExp(/const\s*env\s*=\s*[\'|\"].*[\'|\"]/);
const configPath = path.resolve(__dirname, 'src/config/index.js');
var configInfo = fs.readFileSync(configPath).toString();
const checkMergePath = path.resolve(__dirname, 'check_merge.sh');
const createTagPath = path.resolve(__dirname, 'create_tag.sh');
const branch = process.argv.pop();
var env = configInfo.match(envReg)[0];
var configRes = configInfo.replace(/const\s*env\s*=\s*'.*'/, "const env = 'wechat'");
fs.writeFileSync(configPath, configRes);
const checkMaster = () => {
const checkMasterSpawn = spawn(checkMergePath, [branch]);
checkMasterSpawn.stdout.on('data', (data) => {
console.log(data.toString());
});
checkMasterSpawn.on('close', (code) => {
if (code == 0) {
console.log('check master 成功');
pack();
}
});
}
const pack = () => {
const packSpawn = spawn('cross-env', ['NODE_ENV=production', 'wepy', 'build', '--no-cache']);
packSpawn.stdout.on('data', (data) => {
console.log(data.toString());
});
packSpawn.stderr.on('data', (data) => {
console.log(data.toString());
});
packSpawn.on('close', (code) => {
if (code == 0) {
console.log('打包成功');
createTag();
} else {
console.log(code)
}
});
}
const createTag = () => {
const createTagSpawn = spawn(createTagPath, ['rtag', 'online', 'true']);
createTagSpawn.stdout.on('data', (data) => {
console.log(data.toString());
});
createTagSpawn.on('close', (code) => {
if (code == 0) {
console.log('create tag 成功')
var configRes = configInfo.replace(/const\s*env\s*=\s*'.*'/, env);
fs.writeFileSync(configPath, configRes);
console.log('发布完成')
}
});
}
checkMaster();
check_merge.sh
#!/bin/sh
#检查主干上的提交是否都已合并到分支
function check_error()
{
if [ $? != "0" ];then
echo "$1"
echo "$2"
exit 1
fi
}
function get_branch()
{
git symbolic-ref HEAD 2>&1 | sed -e 's,.*/\(.*\),\1,' | grep -v "not a symbolic"
}
function get_tag()
{
git describe 2>&1 | grep -v " tags"
}
if [ $# != 1 ];then
echo "wrong param! sh check_merge.sh branch|tag"
exit 1;
fi
echo "branch为$1"
work_dir=`pwd`
git config remote.origin.url
check_error "非git目录" "请检查$work_dir"
echo "[check_merge]now is at"
git log | head -3
if [ "x$1" == "xtag" ];then
tag=` get_tag `
else
tag=`get_branch`
fi
msg="目录信息`git status`"
[ "x$tag" != "x" ]
check_error "检索分支出错,模式为$1" "$msg"
msg=`git log origin/master ^${tag} --oneline`
[ "x$msg" == "x" ]
check_error "代码需要merge,分支为$tag,以下的commit没有提交" "$msg"
echo "分支$tag merge检查通过"
create_tag.sh
#!/bin/sh
#生成tag push远端
#函数声明####################################################################################
function check_error()
{
if [ $? != 0 ];then
echo "$1"
exit 1
fi
}
function check_exit()
{
if [ $? == 0 ];then
echo "$1"
exit 0
fi
}
function get_branch()
{
git symbolic-ref HEAD 2>&1 | sed -e 's,.*/\(.*\),\1,' | grep -v "not a symbolic"
}
function get_tag()
{
git describe 2>&1 | grep -v " tags"
}
################################################################################################
work_dir=`pwd`
git config remote.origin.url
check_error "非git目录" "请检查$work_dir"
if [ $# != 3 ];then
echo "wrong param! sh create_tag.sh btag|rtag msg mergeOrNot"
exit 1;
fi
# echo "$1" | grep -P "rtag|btag" >/dev/null 2>&1
# check_error "请输入rtag或btag"
tag=$1"-"`date "+%Y%m%d-%H%M%S"`
msg=$2
need_merge=$3
echo "[merge]now is at"
git log | head -3
current=` get_tag `
[[ "x"$current =~ "xratg" ]]
check_exit "当前commit,无需再打tag"
#[ "x"$current == "x" ] && [[ "x$1" =~ "xrtag" ]]
#check_exit "只有beta能打rtag"
#[ "x"`get_branch` != "x" ] && [[ "x$1" =~ "xrtag" ]]
#check_exit "分支不能打rtag"
[ "x"`get_branch` == "x" ] && [[ "x"$current =~ "xbtag" ]] && [[ "x$1" =~ "xbtag" ]]
check_exit "当前commit无需打新btag"
echo "[merge2]now is at"
git log | head -3
git tag -a $tag -m "$msg"
check_error "生成tag失败,tag为$1"
git reset --hard $tag
echo "[merge3]now is at"
git log | head -3
git rev-parse HEAD
echo "[merge4]now is at"
git log | head -3
git push origin $tag
check_error "push tag到远端失败,mod为$1,tag为$tag"
if [ "$need_merge" == "true" ] ;then
#git push origin ${tag}^{}:master
git checkout master
git fetch origin
git merge origin/master
git reset --hard
git merge $tag
git push origin master
check_error "merge tag $branch 到master失败"
echo “代码已merge主干”
fi