# tapable
# SyncHook
同步钩子。依次执行注册的回调。
class SyncHook {
constructor() {
this.tasks = []
}
tap(name, callback) {
this.tasks.push(callback)
}
call() {
this.tasks.forEach(task => {
task.apply(null, arguments)
})
}
}
const hook = new SyncHook(['name'])
hook.tap('node', function(name) {
console.log(`${name}, node is interesting`)
})
hook.tap('js', function(name) {
console.log(`${name}, js is interesting`)
})
hook.call('jlq')
// jlq, node is interesting
// jlq, js is interesting
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# SyncBailHook
同步保险钩子。依次执行注册的监听函数,遇到返回不是undefined的就中断。
class SyncBailHook {
constructor() {
this.tasks = []
}
tap(name, callback) {
this.tasks.push(callback)
}
call() {
// for循环写法
// const len = this.tasks.length
// for(let i = 0; i < len; i++) {
// const re = this.tasks[i].apply(null, arguments)
// if (re !== undefined) break
// }
// do while写法
let ret, len = 0
do {
ret = this.tasks[len++].apply(null, arguments)
} while (ret === undefined && len < this.tasks.length)
}
}
const hook = new SyncBailHook(['name'])
hook.tap('js', function(name) {
console.log(`${name}, js学完了`)
return undefined
})
hook.tap('node', function(name) {
console.log(`${name}, node学完了`)
return '我太难了,学不动了'
})
hook.tap('webGL', function(name) {
console.log(`${name}, webGL学完了`)
})
hook.call('jlq')
// jlq, js学完了
// jlq, node学完了
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
35
36
37
38
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
35
36
37
38
# SyncWaterfallHook
同步瀑布钩子。依次执行注册的监听函数,把执行结果传给下一个回调,作为其参数继续执行。
class SyncWaterfallHook {
constructor() {
this.tasks = []
}
tap(name, callback) {
this.tasks.push(callback)
}
call(...args) {
// let firstCallback = this.tasks.shift()
// let ret = firstCallback(...args)
// this.tasks.forEach(task => {
// ret = task(ret)
// })
// 解构赋值 + reduce
let [firstCallback, ...otherCallback] = this.tasks
otherCallback.reduce((pre, cur) => {
return cur(pre)
}, firstCallback(...args))
}
}
const hook = new SyncWaterfallHook(['name'])
hook.tap('node', function(name) {
console.log(`${name}开始学习node了`)
return 'node'
})
hook.tap('js', function(name) {
console.log(`${name}学完了,开始学习js`)
})
hook.call('jlq')
// jlq开始学习node了
// node学完了,开始学习js
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
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
# SyncLoopHook
同步循环钩子。依次执行监听函数,如果返回的不是undefined,就反复执行该回调。
class SyncLoopHook {
constructor() {
this.tasks = []
}
tap(name, callback) {
this.tasks.push(callback)
}
call(...args) {
this.tasks.forEach(task => {
let ret
do {
ret = task(...args)
} while (ret !== undefined)
})
}
}
const hook = new SyncLoopHook(['name'])
let index = 1
hook.tap('node', function(name) {
console.log(`${name}学习node的第${index++}天`)
return index === 5 ? undefined : '继续学习node'
})
hook.tap('js', function(name) {
console.log(`${name},node总共学了${index}天,开始学习js`)
})
hook.call('jlq')
// jlq学习node的第1天
// jlq学习node的第2天
// jlq学习node的第3天
// jlq学习node的第4天
// jlq,node总共学了5天,开始学习js
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
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
# AsyncParallelHook
异步并行钩子。异步执行所有监听函数,全部执行完后调用指定回调。
# async写法
class AsyncParallelHook {
constructor() {
this.tasks = []
}
tapAsync(name, callback) {
this.tasks.push(callback)
}
callAsync() {
const args = Array.prototype.slice.call(arguments, 0)
const cb = args.pop()
let index = 0
const fn = () => {
index++
if (index === this.tasks.length) cb()
}
this.tasks.forEach(task => {
task.call(null, ...args, fn)
})
}
}
const hook = new AsyncParallelHook(['name'])
hook.tapAsync('node', function(name, cb) {
setTimeout(() => {
console.log(`${name}一边学node`)
cb()
}, 2000)
})
hook.tapAsync('java', function(name, cb) {
setTimeout(() => {
console.log(`${name}一边学java`)
cb()
}, 1000)
})
hook.callAsync('jlq', function() {
console.log('学完了')
})
// 1s后输出:jlq一边学java
// 再过1s后输出:jlq一边学node
// 学完了
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
35
36
37
38
39
40
41
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
35
36
37
38
39
40
41
# promise写法
class AsyncParallelHook {
constructor() {
this.tasks = []
}
tapPromise(name, callback) {
this.tasks.push(callback)
}
promise() {
const promiseAll = this.tasks.map(task => task.apply(null, arguments))
return Promise.all(promiseAll)
}
}
const hook = new AsyncParallelHook(['name'])
hook.tapPromise('node', function(name) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve()
console.log(`${name}一边学node`)
}, 2000)
})
})
hook.tapPromise('java', function(name) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve()
console.log(`${name}一边学java`)
}, 1000)
})
})
hook.promise('jlq').then(res => {
console.log('学完了')
})
// 1s后输出:jlq一边学java
// 再过1s后输出:jlq一边学node
// 学完了
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
35
36
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
35
36
# AsyncSeriesHook
异步系列钩子。按顺序依次异步执行监听函数(需要等上一个回调执行完),执行完成后调用指定回调。
# async写法
class AsyncSeriesHook {
constructor() {
this.tasks = []
}
tapAsync(name, callback) {
this.tasks.push(callback)
}
callAsync(...args) {
const finalClaaback = args.pop()
let index = 0
const next = () => {
if (index === this.tasks.length) return finalClaaback()
this.tasks[index++](...args, next)
}
next()
}
}
const hook = new AsyncSeriesHook(['name'])
hook.tapAsync('node', function(name, cb) {
setTimeout(() => {
console.log(`${name}先学习node`)
cb()
}, 2000)
})
hook.tapAsync('java', function(name, cb) {
setTimeout(() => {
console.log(`${name}接着学习java`)
cb()
}, 1000)
})
hook.callAsync('jlq', function() {
console.log('都学完了')
})
// 2s后打印:jlq先学习node
// 再过1s后打印:jlq接着学习java
// 都学完了
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
35
36
37
38
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
35
36
37
38
# promise写法
class AsyncSeriesHook {
constructor() {
this.tasks = []
}
tapPromise(name, callback) {
this.tasks.push(callback)
}
promise(...args) {
let [first, ...other] = this.tasks
return other.reduce((pre, cur) => {
return pre.then(res => cur(...args))
}, first(...args))
}
}
const hook = new AsyncSeriesHook(['name'])
hook.tapPromise('node', function(name) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve()
console.log(`${name}先学习node`)
}, 2000)
})
})
hook.tapPromise('java', function(name) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve()
console.log(`${name}接着学习java`)
}, 1000)
})
})
hook.promise('jlq').then(res => {
console.log('都学完了')
})
// 2s后打印:jlq先学习node
// 再过1s后打印:jlq接着学习java
// 都学完了
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
35
36
37
38
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
35
36
37
38
# AsyncSeriesWaterfallHook
异步系列瀑布钩子。依次异步执行监听函数,将上一个钩子的结果传给下一个钩子,全部执行完成后执行指定回调。
class AsyncSeriesWaterfallHook {
constructor() {
this.tasks = []
}
tapAsync(name, callback) {
this.tasks.push(callback)
}
callAsync(...args) {
const finalCallback = args.pop()
let index = 0
const cb = (err, ...result) => {
const task = this.tasks[index]
if (err !== null || !task) return finalCallback()
this.tasks[index](...result, cb)
index++
}
cb(null, ...args)
}
}
const hook = new AsyncSeriesWaterfallHook(['name'])
hook.tapAsync('node', function(name, cb) {
setTimeout(() => {
console.log(`${name}开始学习node`)
cb(null, 'node学完了,')
}, 2000)
})
hook.tapAsync('java', function(name, cb) {
setTimeout(() => {
console.log(`${name}开始学习java`)
cb(null, 'java学完了')
}, 1000)
})
hook.callAsync('jlq', function() {
console.log('全部学完了')
})
// 2s后打印:jlq开始学习node
// 1s后打印:node学完了,开始学习java
// 全部学完了
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
35
36
37
38
39
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
35
36
37
38
39