一个栗子引发的思考

一个栗子引发的思考

前情提要:小 Foo 和小 Bar 是某互联网公司的同事。有一天,小 Foo 交给小 Bar 一个任务……

轮询(Polling)

小 Foo 说明任务之后并没有回到自己的工位,而是站在小 Bar 后边执行了以下方法:

1
2
3
while (!Bar.getRes()) {
console.log("做完了吗?做完了吗??")
}

这就叫轮询

阻塞 (Blocking)

小 Foo 说明任务之后并没有回到自己的工位,而是站在小 Bar 后边执行了以下方法:

1
2
3
while (!Bar.getRes()) {
console.log("做完了吗?做完了吗??")
}

此时小 Foo 是阻塞的,因为 Foo 在等 Bar 的结果什么也没做。

非阻塞 (non-Blocking)

小 Foo 说明任务之后并没有回到自己的工位,而是站在小 Bar 后边执行了以下方法:

1
2
3
4
5
while (!Bar.getRes()) {
Foo.play("炉石传说").finally(() => {
console.log("做完了吗?做完了吗??")
})
}

此时小 Foo 是非阻塞的,因为 Foo 在等 Bar 的时候还玩了炉石传说。

同步 (Synchronous)

小 Foo 说明任务之后,小 Bar 说:“你先回去吧,做完我告诉你”,小 Foo 说:“不行,我就要在这看着你做!你做完了我才能玩炉石传说!”并执行了以下方法:

1
2
3
4
while (!Bar.getRes()) {
console.log("做完了吗?做完了吗??")
}
Foo.play("炉石传说")

此时的工作是同步的,因为只有 Foo Bar 做完了这个工作 Foo 才能玩炉石传说。

异步 (Asynchronous)

小 Foo 说明任务之后,小 Bar 说:“你先回去吧,做完我告诉你”,小 Foo 说:“溜了溜了”,并执行了以下方法:

1
2
3
4
Bar.addEventListener("我做完了", () => {
console.log("你总算做完了")
})
Foo.play("炉石传说")

此时的工作是异步的,因为这个工作还没做完,Foo 已经开始了下一个活动(玩炉石传说)。

并发 (Concurrent)

小 Foo 说明任务 A 之后,发现自己还需要让小 Bar 做任务 B。

小 Bar 先做了任务 A,或者先做了任务 B,或者一会做任务 A 一会做任务 B,或者任务 A 任务 B 同时做,总之,在下班之前交付给了小 Foo。

此时的工作 AB 是宏观并发的,因为在同一时间间隔(下班之前)里,AB 被执行。

并行 (Parallel)

小 Foo 说明任务 A 之后,发现自己还需要让小 Bar 做任务 B。

小 Bar 觉得自己非常厉害,所以他左手做任务 A,右手做任务 B。

此时的工作 AB 在某些时间点是并行,因为在一些时间点上,AB 是同时被执行的。

串行 (Serial)

小 Foo 说明任务 A 之后,发现自己还需要让小 Bar 做任务 B。

小 Bar 觉得自己非常菜,所以精心规划好了工作时间,先做 A,然后做 B,最后检查一遍 A。

此时的工作 AB 是微观串行的,因为在同一时间点,只有一个工作被执行。

函数节流 (throttle)

小 Foo 说明任务之后并没有回到自己的工位,而是站在小 Bar 后边执行了以下方法:

1
2
let cui = () => console.log("做完了吗?做完了吗??")
setInterval(cui, 1)

小 Bar 觉得小 Foo 这样做很不利于工作,于是给小 Foo 加了一层函数,这样小 Foo 无论怎么想催,一分钟最多催一次。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var throttle = function(fn, interval) {
let _self = fn,
timer,
firstTime = true
return () => {
let args = arguments,
_me = this
if (firstTime) {
_self.apply(_me, args)
return (firstTime = false)
}
if (timer) {
return false
}
timer = setTimeOut(() => {
clearTimeOut(timer)
timer = null
_self.apply(_me, args)
}, interval)
}
}
let cui = () => console.log("做完了吗?做完了吗??")
throttle(cui, 1000 * 60)
// 参考《JavaScript设计模式与开发实践》

这个方法叫做函数节流

函数防抖 (debounce)

小 Foo 说明任务之后并没有回到自己的工位,他觉得小 Bar 写的太慢了,于是执行了以下方法:

1
Bar.addEventListener("input", () => console.log("做完了吗?做完了吗??"))

这样小 Bar 每输入一个字,就会听到小 Foo 全方位的“指导”。于是小 Bar 用了一个方法,每次自己停下来思考的时候,小 Foo 就会指导他。

1
2
3
4
5
6
7
8
9
10
function debounce(fn, interval = 300) {
let timeout = null
return function() {
clearTimeout(timeout)
timeout = setTimeout(() => {
fn.apply(this, arguments)
}, interval)
}
}
Bar.addEventListener("input", debounce(() => console.log("做完了吗?做完了吗??"), 1000))

这个方法叫做函数防抖,可用于:搜索框实时显示(不需要每输入一个字都进行一次搜索)

小Foo和小Bar的故事还在继续……

朱耀华_20180913