Skip to content

Commit 1f22bc7

Browse files
committed
Add complex example: logger, task, scheduler
1 parent 6acf6c7 commit 1f22bc7

File tree

1 file changed

+150
-0
lines changed

1 file changed

+150
-0
lines changed

JavaScript/4-scheduler.js

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
'use strict';
2+
3+
const { EventEmitter } = require('events');
4+
5+
class Logger {
6+
static color(level) {
7+
return Logger.COLORS[level] || Logger.COLORS.info;
8+
}
9+
log(level, s) {
10+
const date = new Date().toISOString();
11+
const color = Logger.color(level);
12+
console.log(color + date + '\t' + s + '\x1b[0m');
13+
}
14+
warn(s) {
15+
this.log('warn', s);
16+
}
17+
error(s) {
18+
this.log('error', s);
19+
}
20+
info(s) {
21+
this.log('info', s);
22+
}
23+
}
24+
25+
Logger.COLORS = {
26+
warn: '\x1b[1;33m',
27+
error: '\x1b[0;31m',
28+
info: '\x1b[1;37m',
29+
};
30+
31+
class Task extends EventEmitter {
32+
constructor(name, time, exec) {
33+
super();
34+
this.name = name;
35+
if (typeof time === 'number') {
36+
this.time = Date.now() + time;
37+
this.set = setInterval;
38+
this.clear = clearInterval;
39+
} else {
40+
this.time = new Date(time).getTime();
41+
this.set = setTimeout;
42+
this.clear = clearTimeout;
43+
}
44+
this.exec = exec;
45+
this.running = false;
46+
this.count = 0;
47+
this.timer = null;
48+
}
49+
get active() {
50+
return !!this.timer;
51+
}
52+
start() {
53+
this.stop();
54+
if (this.running) return false;
55+
const time = this.time - Date.now();
56+
if (time < 0) return false;
57+
this.timer = this.set(() => {
58+
this.run();
59+
}, time);
60+
return true;
61+
}
62+
stop() {
63+
if (!this.active || this.running) return false;
64+
this.clear(this.timer);
65+
this.timer = null;
66+
return true;
67+
}
68+
run() {
69+
if (!this.active || this.running) return false;
70+
this.running = true;
71+
this.emit('begin');
72+
this.exec((err, res) => {
73+
if (err) this.emit('error', err);
74+
this.emit('end', res);
75+
this.count++;
76+
this.running = false;
77+
});
78+
return true;
79+
}
80+
}
81+
82+
class Scheduler extends EventEmitter {
83+
constructor() {
84+
super();
85+
this.tasks = new Map();
86+
this.logger = new Logger();
87+
}
88+
task(name, time, exec) {
89+
this.stop(name);
90+
const task = new Task(name, time, exec);
91+
this.tasks.set(name, task);
92+
task.on('error', err => {
93+
this.logger.error(task.name + '\t' + err.message);
94+
this.emit('error', err);
95+
});
96+
task.on('begin', () => {
97+
this.logger.info(task.name + '\tbegin');
98+
});
99+
task.on('end', res => {
100+
this.logger.warn(task.name + '\tend\t' + res);
101+
});
102+
task.start();
103+
return task;
104+
}
105+
stop(name) {
106+
const task = this.tasks.get(name);
107+
if (task) {
108+
task.stop();
109+
this.tasks.delete(name);
110+
}
111+
}
112+
stopAll() {
113+
for (const name of this.tasks.keys()) {
114+
this.stop(name);
115+
}
116+
}
117+
}
118+
119+
// Usage
120+
121+
const scheduler = new Scheduler();
122+
123+
scheduler.on('error', err => {
124+
console.log(err.stack);
125+
//process.exit(1);
126+
});
127+
128+
scheduler.task('name1', '2019-03-12T14:30Z', done => {
129+
setTimeout(() => {
130+
done(null, 'task successed');
131+
}, 1000);
132+
});
133+
134+
scheduler.task('name2', '2019-03-12T14:31Z', done => {
135+
setTimeout(() => {
136+
done(new Error('task failed'));
137+
}, 1100);
138+
});
139+
140+
scheduler.task('name3', 500, done => {
141+
setTimeout(() => {
142+
done(null, 'task successed');
143+
}, 1200);
144+
});
145+
146+
scheduler.task('name4', 800, done => {
147+
setTimeout(() => {
148+
done(new Error('task failed'));
149+
}, 2000);
150+
});

0 commit comments

Comments
 (0)