0%

背景

众所周知,数据库建立索引后速度会有极大的提升.但前提是正确的建立索引,否则数据库查询就不会走索引,而导致慢查询,不仅影响当前服务的性能,甚至可能影响其他使用同一数据库的服务的性能.

而索引分为独立索引和组合索引.

独立索引(Single field index)

对单独字段建立索引,例如:

1
{ "name": 1 }

1 表示升序索引,-1 表示降序索引

查询条件为单一条件时有效,当查询条件为多个条件组合时,不会一一匹配独立索引

独立索引的 sort 排序

对于独立索引来说,由于 MongoDB index 本身支持顺序查找,所以对于独立索引来说不管你是{ sort: 1} 还是{ sort: -1 }都是一样的

组合索引(Compound index)

当查询条件为多个条件组合时,需要建立组合索引,例如:

1
2
3
4
5
6
7
{
"distributorNo": 1,
"payEnv": 1,
"orderStatus": 1,
"region": 1,
"createdAt": -1
}

组合索引中条件的顺序对索引的性能有至关重要的影响,比如索引 {userid:1, score:-1} 首先根据 userid 排序,然后再在每个 userid 中根据 score 排序。

使用组合索引需要满足 prefix 原则

Index prefix 是指组合索引字段的左前缀子集,考虑以下索引:

阅读全文 »

模块间传参

传参用的字段名不能用驼峰或者下划线,要全小写
到 B页面用 props 声明,字段名要加引号,之后使用方式和 data 声明的变量一样,在 js 内用 this.引用,在 HTML 内直接引用

1
2
// A 模块中引用 B 模块
<videoRegionStatCharts :topicid="topicId" :timestamp="listQuery.timestamp"/>
1
2
3
4
5
6
7
8
9
10
11
// B 模块
export default {
components: { timePicker },
props: ['topicid', 'timestamp'],
data() {
return {
listQuery: {
}
}
}
}

watch 方法

watch 监听的字段不能是 data 声明的字段
用 computed或者 props 声明的字段可以被 watch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
props: ['topicid', 'timestamp','regionparam'],
data() {
return {
listQuery: {
region: this.regionparam,
}
}
},
computed: { // 这里要监听 this.listQuery.region,不能直接监听 data 声明的变量,要用 computed 声明并返回 this.listQuery.region 实现绑定
region: function() {
return this.listQuery.region
}
},
watch: {
topicid: function(val) {
this.listQuery.topicId = val
this.drawLine()
},
region: function(val) { // 这里监听的其实是 this.listQuery.region
this.$emit('changeRegion', val) // 向父组件传参
},
timestamp: function(val) {
this.listQuery.timestamp = val
this.drawLine()
}
}

子组件向父组件传参

1
2
3
4
5
6
<videoRegionStatCharts
:topicid="topicId"
:regionparam="listQuery.region"
:timestamp="listQuery.timestamp"
@changeRegion="handleChangeRegion"
/>
1
2
3
4
5
6
7
8
9
10
<!--子组件传参-->
region: function(val) {
this.$emit('changeRegion', val)
}
<!--父组件响应-->
handleChangeRegion(val) {
this.listQuery.region = val
this.handleFilter()
}

通过:regionparam向子组件传参,子组件再通过listQuery.region: this.regionparam绑定参数,然后通过 computed 声明一个新变量来监听子组件参数的变化,如果子组件的这个参数变了会通过this.$emit('changeRegion', val)向父组件发送通知,父组件用handleChangeRegion响应子组件的传参
最终实现双向绑定

Docker

在了解 Docker 之前先了解虚拟机,虚拟机就是在你的操作系统里面,装一个软件,然后通过这个软件,再模拟一台甚至多台“子电脑”出来。而Docker这样的容器技术,也是虚拟化技术,属于轻量级的虚拟化

虚拟机虽然可以隔离出很多“子电脑”,但占用空间更大,启动更慢,虚拟机软件可能还要花钱(例如VMWare)。
而容器技术恰好没有这些缺点。它不需要虚拟出整个操作系统,只需要虚拟一个小规模的环境(类似“沙箱”)。它启动时间很快,几秒钟就能完成。而且,它对资源的利用率很高(一台主机可以同时运行几千个Docker容器)。此外,它占的空间很小,虚拟机一般要几GB到几十GB的空间,而容器只需要MB级甚至KB级。

阅读全文 »

背景

经常在用的一个配置管理页面在产品迭代了几个版本以后发现配置页越来越长,但是又不想做成两列(觉得丑),所以就自己写了一个目录,点击以后页面会滑动到对应的配置项.
一开始是打算用 a 标签的 href 来做,但是发现这个方式点击以后会改变 URL,而且是直接跳到指定的标签,用户体验不是很好,就改用scrollIntoView

scrollIntoView事件

Element.scrollIntoView() 方法让当前的元素滚动到浏览器窗口的可视区域内
只要用document.getElementById()方法找到要跳转的 element,然后就可以用scrollIntoView方法实现跳转,代码如下:

1
2
3
4
document.getElementById(target).scrollIntoView({
behavior: 'smooth',
block: 'start'
})

scrollIntoView方法有 3 个多态,分别是不传参数,传 Boolean型的参数,传 Object 型的参数.

element.scrollIntoView(); // 等同于element.scrollIntoView(true)
element.scrollIntoView(alignToTop); // Boolean型参数
element.scrollIntoView(scrollIntoViewOptions); // Object型参数

阅读全文 »

1.介绍

Node.js 底层使用的是 glibc 库,这些错误信息都是 glibc 库在 socket 连接时使用的 connect 函数中定义的错误类型,当然,v8在使用glibc库时也会加入一些自定义的错误类型,但许多错误情况还是和glibc中的定义一致的。

connect 函数的定义为:int connect (int socket, struct sockaddr addr, socklen_t length)

connect 函数会使用文件描述符(file descriptor)socket表示的 socket 发起连接,socket 地址通过 addr 和 length 这两个参数来指定。(这个 socket 一般是其他机器的 socket,而且必须已经配置成了服务器)。

一般情况下,connect 函数会等待服务器响应请求才返回。当然也可以将 socket 设置为非阻塞模式来不等待响应就快速返回(可以参考下 nginx 是怎么使用 socket 的)。

2.错误类型

connect 函数正常的返回值为 0,在有错误时会返回 -1。函数中定义了如下错误条件:

  • EBADF:socket 不是有效的文件描述符(file descriptor)。
阅读全文 »

背景

分享到微博或者推特都有 140 字的限制,所以最近产品提出一个分享 URL 要做成短链接的需求,便在网上查询了一下资料,综合下来,总结了几种算法.

算法

总的来说就是把长的 URL 通过一个算法得出一个 6 位左右的短链,再把这个映射关系保存起来,下次有用户访问短链的时候我们能找到他对应的长链.并通过301 或者 302 重定向到原来的 URL 上.

1. 自增 id 转 62 进制

从数据库或者 redis 里取一个自增数据,然后十进制转化成 62 进制,这样短链就永远不会重复,适合于原始 URL 1 对多的情况,也就是一个长链接每次分享都生成不一样的短链接.

就算是一亿对应的 62 进制数也就是 6LAze,短短的 5 位.

最小的 7 位 62 进制数对应的十进制数是 56800235584,五百六十八亿多,远超当前的所有URL 总和.所以 6 位数的 62 进制是肯定够用的.

阅读全文 »

背景

今天在写代码的时候遇到一个 bug,价格竟然显示了 null.非常莫名其妙,我明明做了错误处理,打断点之后发现问题

1
2
3
4
5
if (item.customPrice >= 0) {
item.price = item.customPrice;
} else {
item.price = 10;
}

也就是说 item.customPrice 需要是数字且大于等于0,才会赋值给price,否则会调用默认值.
但是我发现当 customPrice = null 时这个判断也会为真值,此时 item.price = null;

null >= 0?那 null == 0?

我用 Chrome 的 console 写了几个判断


发现只有 null >= 0null <= 0的判断为真值,其他都是 false

查资料

如果想明确,这个问题具体是怎么回事,那么我们需要重新来回顾一下我们的 ECMAScript Language Specification (HTML version),翻译过来就是ECMAScript语言规范(HTML版本)。

内部相等性运算算法

首先我们来看一下 ES3 关于 内部相等性运算的算法实现。

阅读全文 »

Vue-store

场景

有些时候需要在当前页面去修改其他页面的数据,如果使用 localStorage那需要页面重新加载,因为localStorage是数据不是在 Vue 项目本身的,而是存放在浏览器中的,这需要页面重新加载,样式才会重新加载数据并渲染.这在用户体验上是很不友好的事,这个时候就需要使用 store.

store

store 你可以理解为一个全局变量池,其中可以存放变量或者方法.
首先需要在 store里注册这个变量和改变它的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// store.modules
const app = {
state: {
isTopMenu: true,
distributorNo: 0
},
mutations: {
SWITCH_MENU: (state, isTopMenu) => {
state.isTopMenu = isTopMenu
},
CHANGE_DISTRIBUTORNO: (state, distributorNo) => {
state.distributorNo = distributorNo
}
},
actions: {
SwitchMenu({ commit }, isTopMenu) {
commit('SWITCH_MENU', isTopMenu)
},
ChangeDistributorNo({ commit }, distributorNo) {
commit('CHANGE_DISTRIBUTORNO', distributorNo)
}
}
}
export default app

// 在store->index.js 里初始化对象
import app from './modules/app'
const store = new Vuex.Store({
modules: {
app
},
getters
})
export default store

这样我们就有了 state.distributorNo, ChangeDistributorNo(), CHANGE_DISTRIBUTORNO

store.dispatch 调用

阅读全文 »

JavaScript 的原型链

JavaScript 的原型链关系到js 的对象,方法实例化的原理,弄懂原型链就可以明白 js 封装继承的原理.对理解js 的面向对象有很大的帮助.在 ES6 中引入了 class 关键字,但那只是语法糖,JavaScript 仍然是基于原型链的.
原型链主要是由 2 个对象实现的: __proto__prototype

__proto__和 prototype

JavaScript 的所有对象都有__proto__这个属性,其实__proto__就是一个指针, 他指向实例化他这个对象的原始对象的 prototype 对象.

1
2
3
4
class Book {} // function Book() {}
const mathBook = new Book();
// 这里mathBook.__proto__ === Book.prototype
// 这就是__proto__指向实例化他的原始对象的 prototype.

prototype 是所有的函数对象都有的属性,当一个函数对象被 new 实例化时,他的 prototype 里的属性和方法都会被复制一份,放到实例化的对象里,并且 prototype 这个对象也有__proto__对象,实例化的时候还会把__proto__指向的对象的 prototype 里的属性和方法也复制一份.也就实现了继承.

1
2
3
4
class Book {}
const mathBook = new Book();
console.log(Book.prototype.__proto__ === Object.prototype) // true
// 但是 mathBook 是没有 prototype 属性的,因为他是一个实例化对象,而不是一个函数,js 中的类是用函数模拟出来的,全依赖这个 prototype

JavaScript 的基本数据类型

JavaScript 的基本数据类型也是通过这种方法实现的.

阅读全文 »

配置 firebase

在创建了 firebase 项目以后,首先要将 Firebase Admin SDK 添加到服务器,然后生成配置 json 文件

firebase添加到服务器

点击生成 JSON 文件以后,需备份保存,以免丢失

初始化 firebase SDK

阅读全文 »