ee-core 2.9.2 → 2.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +65 -65
  3. package/addon/index.js +34 -34
  4. package/addon/window/index.js +98 -98
  5. package/bin/tools.js +8 -8
  6. package/config/cache.js +41 -38
  7. package/config/config.default.js +331 -330
  8. package/config/index.js +75 -73
  9. package/const/channel.js +17 -17
  10. package/const/index.js +8 -8
  11. package/controller/baseContextClass.js +34 -34
  12. package/controller/index.js +34 -34
  13. package/core/index.js +10 -10
  14. package/core/lib/ee.js +216 -216
  15. package/core/lib/loader/context_loader.js +106 -106
  16. package/core/lib/loader/ee_loader.js +435 -435
  17. package/core/lib/loader/file_loader.js +326 -326
  18. package/core/lib/loader/mixin/addon.js +32 -32
  19. package/core/lib/loader/mixin/config.js +130 -130
  20. package/core/lib/loader/mixin/controller.js +125 -125
  21. package/core/lib/loader/mixin/service.js +28 -28
  22. package/core/lib/utils/base_context_class.js +34 -34
  23. package/core/lib/utils/function.js +30 -30
  24. package/core/lib/utils/index.js +133 -133
  25. package/core/lib/utils/sequencify.js +59 -59
  26. package/core/lib/utils/timing.js +77 -77
  27. package/cross/index.js +183 -183
  28. package/cross/spawnProcess.js +183 -183
  29. package/ee/appLoader.js +48 -48
  30. package/ee/application.js +99 -99
  31. package/ee/baseApp.js +103 -102
  32. package/ee/eeApp.js +408 -408
  33. package/ee/index.js +57 -57
  34. package/electron/app/index.js +64 -58
  35. package/electron/index.js +19 -19
  36. package/electron/window/index.js +73 -73
  37. package/electron/window/winState.js +186 -186
  38. package/exception/index.js +112 -112
  39. package/html/boot.html +98 -98
  40. package/html/cross-failure.html +28 -28
  41. package/html/failure.html +28 -28
  42. package/html/index.js +13 -13
  43. package/httpclient/index.js +161 -161
  44. package/index.js +54 -54
  45. package/jobs/baseJobClass.js +16 -16
  46. package/jobs/child/app.js +65 -65
  47. package/jobs/child/forkProcess.js +145 -145
  48. package/jobs/child/index.js +82 -82
  49. package/jobs/child-pool/index.js +213 -213
  50. package/jobs/index.js +8 -8
  51. package/jobs/load-balancer/algorithm/index.js +11 -11
  52. package/jobs/load-balancer/algorithm/minimumConnection.js +18 -18
  53. package/jobs/load-balancer/algorithm/polling.js +11 -11
  54. package/jobs/load-balancer/algorithm/random.js +9 -9
  55. package/jobs/load-balancer/algorithm/specify.js +14 -14
  56. package/jobs/load-balancer/algorithm/weights.js +21 -21
  57. package/jobs/load-balancer/algorithm/weightsMinimumConnection.js +29 -29
  58. package/jobs/load-balancer/algorithm/weightsPolling.js +22 -22
  59. package/jobs/load-balancer/algorithm/weightsRandom.js +16 -16
  60. package/jobs/load-balancer/consts.js +9 -9
  61. package/jobs/load-balancer/index.js +201 -201
  62. package/jobs/load-balancer/scheduler.js +31 -31
  63. package/jobs/renderer/index.js +141 -141
  64. package/jobs/renderer/loadView.js +40 -40
  65. package/jobs/unification.js +63 -63
  66. package/loader/index.js +172 -172
  67. package/log/index.js +68 -68
  68. package/log/logger.js +86 -80
  69. package/main/index.js +56 -56
  70. package/message/childMessage.js +54 -54
  71. package/message/index.js +18 -18
  72. package/old-utils/index.js +91 -91
  73. package/package.json +38 -38
  74. package/ps/index.js +371 -371
  75. package/services/baseContextClass.js +34 -34
  76. package/services/index.js +40 -40
  77. package/socket/httpServer.js +147 -147
  78. package/socket/index.js +81 -81
  79. package/socket/io.js +27 -27
  80. package/socket/ipcServer.js +112 -112
  81. package/socket/socketServer.js +69 -67
  82. package/storage/index.js +38 -38
  83. package/storage/jsondb/adapters/Base.js +23 -23
  84. package/storage/jsondb/adapters/FileSync.js +64 -52
  85. package/storage/jsondb/main.js +55 -42
  86. package/storage/jsondbStorage.js +195 -195
  87. package/storage/sqliteStorage.js +123 -123
  88. package/utils/co.js +237 -237
  89. package/utils/copyto.js +160 -160
  90. package/utils/depd/index.js +538 -538
  91. package/utils/depd/lib/browser/index.js +77 -77
  92. package/utils/extend.js +73 -73
  93. package/utils/get-port/index.d.ts +64 -64
  94. package/utils/get-port/index.js +148 -148
  95. package/utils/helper.js +220 -220
  96. package/utils/index.js +160 -160
  97. package/utils/ip.js +261 -261
  98. package/utils/is.js +145 -145
  99. package/utils/json.js +72 -72
  100. package/utils/pargv.js +263 -263
  101. package/utils/time/index.js +19 -19
  102. package/utils/time/ms.js +162 -162
  103. package/utils/wrap.js +35 -35
@@ -1,82 +1,82 @@
1
- const EventEmitter = require('events');
2
- const ForkProcess = require('./forkProcess');
3
- const Loader = require('../../loader');
4
- const Channel = require('../../const/channel');
5
- const Conf = require('../../config');
6
-
7
- class ChildJob extends EventEmitter {
8
-
9
- constructor() {
10
- super();
11
- this.jobs = {};
12
- this.config = {};
13
-
14
- const cfg = Conf.getValue('jobs');
15
- if (cfg) {
16
- this.config = cfg;
17
- }
18
-
19
- this._initEvents();
20
- }
21
-
22
- /**
23
- * 初始化监听
24
- */
25
- _initEvents() {
26
- this.on(Channel.events.childProcessExit, (data) => {
27
- delete this.jobs[data.pid];
28
- });
29
- this.on(Channel.events.childProcessError, (data) => {
30
- delete this.jobs[data.pid];
31
- });
32
- }
33
-
34
- /**
35
- * 执行一个job文件
36
- */
37
- exec(filepath, params = {}, opt = {}) {
38
- const jobPath = Loader.getFullpath(filepath);
39
- const proc = this.createProcess(opt);
40
- const cmd = 'run';
41
- proc.dispatch(cmd, jobPath, params);
42
-
43
- return proc;
44
- }
45
-
46
- /**
47
- * 创建子进程
48
- */
49
- createProcess(opt = {}) {
50
- let options = Object.assign({
51
- processArgs: {
52
- type: 'childJob'
53
- }
54
- }, opt);
55
- const proc = new ForkProcess(this, options);
56
- if (!proc) {
57
- let errorMessage = `[ee-core] [jobs/child] Failed to obtain the child process !`
58
- throw new Error(errorMessage);
59
- }
60
- this.jobs[proc.pid] = proc;
61
-
62
- return proc;
63
- }
64
-
65
- /**
66
- * 获取当前pids
67
- */
68
- getPids() {
69
- let pids = Object.keys(this.jobs);
70
- return pids;
71
- }
72
-
73
- /**
74
- * 异步执行一个job文件 todo this指向
75
- */
76
- async execPromise(filepath, params = {}, opt = {}) {
77
- return this.exec(filepath, params, opt);
78
- }
79
-
80
- }
81
-
82
- module.exports = ChildJob;
1
+ const EventEmitter = require('events');
2
+ const ForkProcess = require('./forkProcess');
3
+ const Loader = require('../../loader');
4
+ const Channel = require('../../const/channel');
5
+ const Conf = require('../../config/cache');
6
+
7
+ class ChildJob extends EventEmitter {
8
+
9
+ constructor() {
10
+ super();
11
+ this.jobs = {};
12
+ this.config = {};
13
+
14
+ const cfg = Conf.getValue('jobs');
15
+ if (cfg) {
16
+ this.config = cfg;
17
+ }
18
+
19
+ this._initEvents();
20
+ }
21
+
22
+ /**
23
+ * 初始化监听
24
+ */
25
+ _initEvents() {
26
+ this.on(Channel.events.childProcessExit, (data) => {
27
+ delete this.jobs[data.pid];
28
+ });
29
+ this.on(Channel.events.childProcessError, (data) => {
30
+ delete this.jobs[data.pid];
31
+ });
32
+ }
33
+
34
+ /**
35
+ * 执行一个job文件
36
+ */
37
+ exec(filepath, params = {}, opt = {}) {
38
+ const jobPath = Loader.getFullpath(filepath);
39
+ const proc = this.createProcess(opt);
40
+ const cmd = 'run';
41
+ proc.dispatch(cmd, jobPath, params);
42
+
43
+ return proc;
44
+ }
45
+
46
+ /**
47
+ * 创建子进程
48
+ */
49
+ createProcess(opt = {}) {
50
+ let options = Object.assign({
51
+ processArgs: {
52
+ type: 'childJob'
53
+ }
54
+ }, opt);
55
+ const proc = new ForkProcess(this, options);
56
+ if (!proc) {
57
+ let errorMessage = `[ee-core] [jobs/child] Failed to obtain the child process !`
58
+ throw new Error(errorMessage);
59
+ }
60
+ this.jobs[proc.pid] = proc;
61
+
62
+ return proc;
63
+ }
64
+
65
+ /**
66
+ * 获取当前pids
67
+ */
68
+ getPids() {
69
+ let pids = Object.keys(this.jobs);
70
+ return pids;
71
+ }
72
+
73
+ /**
74
+ * 异步执行一个job文件 todo this指向
75
+ */
76
+ async execPromise(filepath, params = {}, opt = {}) {
77
+ return this.exec(filepath, params, opt);
78
+ }
79
+
80
+ }
81
+
82
+ module.exports = ChildJob;
@@ -1,213 +1,213 @@
1
- const EventEmitter = require('events');
2
- const LoadBalancer = require('../load-balancer');
3
- const Loader = require('../../loader');
4
- const ForkProcess = require('../child/forkProcess');
5
- const Channel = require('../../const/channel');
6
- const Helper = require('../../utils/helper');
7
- const Conf = require('../../config');
8
-
9
- class ChildPoolJob extends EventEmitter {
10
-
11
- constructor(opt = {}) {
12
- super();
13
- let options = Object.assign({
14
- weights: [],
15
- }, opt);
16
-
17
- this.config = {};
18
- this.boundMap = new Map();
19
- this.children = {};
20
- this.min = 3;
21
- this.max = 6;
22
- this.strategy = 'polling';
23
- this.weights = new Array(this.max).fill().map((v, i) => {
24
- let w = Helper.validValue(options.weights[i]) ? options.weights[i] : 1
25
- return w;
26
- });
27
-
28
- let lbOpt = {
29
- algorithm: LoadBalancer.Algorithm.polling,
30
- targets: [],
31
- }
32
- this.LB = new LoadBalancer(lbOpt);
33
-
34
- const cfg = Conf.getValue('jobs');
35
- if (cfg) {
36
- this.config = cfg;
37
- }
38
-
39
- this._initEvents();
40
- }
41
-
42
- /**
43
- * 初始化监听
44
- */
45
- _initEvents() {
46
- this.on(Channel.events.childProcessExit, (data) => {
47
- this._removeChild(data.pid);
48
- });
49
- this.on(Channel.events.childProcessError, (data) => {
50
- this._removeChild(data.pid);
51
- });
52
- }
53
-
54
- /**
55
- * 移除对象
56
- */
57
- _removeChild(pid) {
58
- const length = Object.keys(this.children).length;
59
- const lbOpt = {
60
- id: pid,
61
- weight: this.weights[length - 1],
62
- }
63
- this.LB.del(lbOpt);
64
- delete this.children[pid];
65
- }
66
-
67
- /**
68
- * 创建一个池子
69
- */
70
- async create(number = 3) {
71
- if (number < 0 || number > this.max) {
72
- throw new Error(`[ee-core] [jobs/child-pool] The number is invalid !`);
73
- }
74
- let currentNumber = this.children.length;
75
- if (currentNumber > this.max) {
76
- throw new Error(`[ee-core] [jobs/child-pool] The number of current processes number: ${currentNumber} is greater than the maximum: ${this.max} !`);
77
- }
78
-
79
- if (number + currentNumber > this.max) {
80
- number = this.max - currentNumber;
81
- }
82
-
83
- // args
84
- let options = Object.assign({
85
- processArgs: {
86
- type: 'childPoolJob'
87
- }
88
- }, {});
89
- for (let i = 1; i <= number; i++) {
90
- let task = new ForkProcess(this, options);
91
- this._childCreated(task);
92
- }
93
-
94
- let pids = Object.keys(this.children);
95
-
96
- return pids;
97
- }
98
-
99
- /**
100
- * 子进程创建后处理
101
- */
102
- _childCreated(childProcess) {
103
- let pid = childProcess.pid;
104
- this.children[pid] = childProcess;
105
-
106
- const length = Object.keys(this.children).length;
107
- let lbTask = {
108
- id: pid,
109
- weight: this.weights[length - 1],
110
- }
111
- this.LB.add(lbTask);
112
- }
113
-
114
- /**
115
- * 执行一个job文件
116
- */
117
- run(filepath, params = {}) {
118
- const jobPath = Loader.getFullpath(filepath);
119
- const childProcess = this.getChild();
120
- childProcess.dispatch('run', jobPath, params);
121
-
122
- return childProcess;
123
- }
124
-
125
- /**
126
- * 异步执行一个job文件
127
- */
128
- async runPromise(filepath, params = {}) {
129
- return this.run(filepath, params);
130
- }
131
-
132
- /**
133
- * 获取绑定的进程对象
134
- */
135
- getBoundChild(boundId) {
136
- let proc;
137
- const boundPid = this.boundMap.get(boundId);
138
- if (boundPid) {
139
- proc = this.children[boundPid];
140
- return proc;
141
- }
142
-
143
- // 获取进程并绑定
144
- proc = this.getChild();
145
- this.boundMap.set(boundId, proc.pid);
146
-
147
- return proc;
148
- }
149
-
150
- /**
151
- * 通过pid获取一个子进程对象
152
- */
153
- getChildByPid(pid) {
154
- let proc = this.children[pid] || null;
155
- return proc;
156
- }
157
-
158
- /**
159
- * 获取一个子进程对象
160
- */
161
- getChild() {
162
- let proc;
163
- const currentPids = Object.keys(this.children);
164
-
165
- // 没有则创建
166
- if (currentPids.length == 0) {
167
- let subIds = this.create(1);
168
- proc = this.children[subIds[0]];
169
- } else {
170
- // 从池子中获取一个
171
- let onePid = this.LB.pickOne().id;
172
- proc = this.children[onePid];
173
- }
174
-
175
- if (!proc) {
176
- let errorMessage = `[ee-core] [jobs/child-pool] Failed to obtain the child process !`
177
- throw new Error(errorMessage);
178
- }
179
-
180
- return proc;
181
- }
182
-
183
- /**
184
- * 获取当前pids
185
- */
186
- getPids() {
187
- let pids = Object.keys(this.children);
188
- return pids;
189
- }
190
-
191
- /**
192
- * kill all
193
- * @param type {String} - 'sequence' | 'parallel'
194
- */
195
- killAll(type = 'parallel') {
196
- let i = 1;
197
- Object.keys(this.children).forEach(key => {
198
- let proc = this.children[key];
199
- if (proc) {
200
- if (type == 'sequence') {
201
- setTimeout(()=>{
202
- proc.kill();
203
- }, i * 1000)
204
- i++;
205
- } else {
206
- proc.kill();
207
- }
208
- }
209
- });
210
- }
211
- }
212
-
213
- module.exports = ChildPoolJob;
1
+ const EventEmitter = require('events');
2
+ const LoadBalancer = require('../load-balancer');
3
+ const Loader = require('../../loader');
4
+ const ForkProcess = require('../child/forkProcess');
5
+ const Channel = require('../../const/channel');
6
+ const Helper = require('../../utils/helper');
7
+ const Conf = require('../../config/cache');
8
+
9
+ class ChildPoolJob extends EventEmitter {
10
+
11
+ constructor(opt = {}) {
12
+ super();
13
+ let options = Object.assign({
14
+ weights: [],
15
+ }, opt);
16
+
17
+ this.config = {};
18
+ this.boundMap = new Map();
19
+ this.children = {};
20
+ this.min = 3;
21
+ this.max = 6;
22
+ this.strategy = 'polling';
23
+ this.weights = new Array(this.max).fill().map((v, i) => {
24
+ let w = Helper.validValue(options.weights[i]) ? options.weights[i] : 1
25
+ return w;
26
+ });
27
+
28
+ let lbOpt = {
29
+ algorithm: LoadBalancer.Algorithm.polling,
30
+ targets: [],
31
+ }
32
+ this.LB = new LoadBalancer(lbOpt);
33
+
34
+ const cfg = Conf.getValue('jobs');
35
+ if (cfg) {
36
+ this.config = cfg;
37
+ }
38
+
39
+ this._initEvents();
40
+ }
41
+
42
+ /**
43
+ * 初始化监听
44
+ */
45
+ _initEvents() {
46
+ this.on(Channel.events.childProcessExit, (data) => {
47
+ this._removeChild(data.pid);
48
+ });
49
+ this.on(Channel.events.childProcessError, (data) => {
50
+ this._removeChild(data.pid);
51
+ });
52
+ }
53
+
54
+ /**
55
+ * 移除对象
56
+ */
57
+ _removeChild(pid) {
58
+ const length = Object.keys(this.children).length;
59
+ const lbOpt = {
60
+ id: pid,
61
+ weight: this.weights[length - 1],
62
+ }
63
+ this.LB.del(lbOpt);
64
+ delete this.children[pid];
65
+ }
66
+
67
+ /**
68
+ * 创建一个池子
69
+ */
70
+ async create(number = 3) {
71
+ if (number < 0 || number > this.max) {
72
+ throw new Error(`[ee-core] [jobs/child-pool] The number is invalid !`);
73
+ }
74
+ let currentNumber = this.children.length;
75
+ if (currentNumber > this.max) {
76
+ throw new Error(`[ee-core] [jobs/child-pool] The number of current processes number: ${currentNumber} is greater than the maximum: ${this.max} !`);
77
+ }
78
+
79
+ if (number + currentNumber > this.max) {
80
+ number = this.max - currentNumber;
81
+ }
82
+
83
+ // args
84
+ let options = Object.assign({
85
+ processArgs: {
86
+ type: 'childPoolJob'
87
+ }
88
+ }, {});
89
+ for (let i = 1; i <= number; i++) {
90
+ let task = new ForkProcess(this, options);
91
+ this._childCreated(task);
92
+ }
93
+
94
+ let pids = Object.keys(this.children);
95
+
96
+ return pids;
97
+ }
98
+
99
+ /**
100
+ * 子进程创建后处理
101
+ */
102
+ _childCreated(childProcess) {
103
+ let pid = childProcess.pid;
104
+ this.children[pid] = childProcess;
105
+
106
+ const length = Object.keys(this.children).length;
107
+ let lbTask = {
108
+ id: pid,
109
+ weight: this.weights[length - 1],
110
+ }
111
+ this.LB.add(lbTask);
112
+ }
113
+
114
+ /**
115
+ * 执行一个job文件
116
+ */
117
+ run(filepath, params = {}) {
118
+ const jobPath = Loader.getFullpath(filepath);
119
+ const childProcess = this.getChild();
120
+ childProcess.dispatch('run', jobPath, params);
121
+
122
+ return childProcess;
123
+ }
124
+
125
+ /**
126
+ * 异步执行一个job文件
127
+ */
128
+ async runPromise(filepath, params = {}) {
129
+ return this.run(filepath, params);
130
+ }
131
+
132
+ /**
133
+ * 获取绑定的进程对象
134
+ */
135
+ getBoundChild(boundId) {
136
+ let proc;
137
+ const boundPid = this.boundMap.get(boundId);
138
+ if (boundPid) {
139
+ proc = this.children[boundPid];
140
+ return proc;
141
+ }
142
+
143
+ // 获取进程并绑定
144
+ proc = this.getChild();
145
+ this.boundMap.set(boundId, proc.pid);
146
+
147
+ return proc;
148
+ }
149
+
150
+ /**
151
+ * 通过pid获取一个子进程对象
152
+ */
153
+ getChildByPid(pid) {
154
+ let proc = this.children[pid] || null;
155
+ return proc;
156
+ }
157
+
158
+ /**
159
+ * 获取一个子进程对象
160
+ */
161
+ getChild() {
162
+ let proc;
163
+ const currentPids = Object.keys(this.children);
164
+
165
+ // 没有则创建
166
+ if (currentPids.length == 0) {
167
+ let subIds = this.create(1);
168
+ proc = this.children[subIds[0]];
169
+ } else {
170
+ // 从池子中获取一个
171
+ let onePid = this.LB.pickOne().id;
172
+ proc = this.children[onePid];
173
+ }
174
+
175
+ if (!proc) {
176
+ let errorMessage = `[ee-core] [jobs/child-pool] Failed to obtain the child process !`
177
+ throw new Error(errorMessage);
178
+ }
179
+
180
+ return proc;
181
+ }
182
+
183
+ /**
184
+ * 获取当前pids
185
+ */
186
+ getPids() {
187
+ let pids = Object.keys(this.children);
188
+ return pids;
189
+ }
190
+
191
+ /**
192
+ * kill all
193
+ * @param type {String} - 'sequence' | 'parallel'
194
+ */
195
+ killAll(type = 'parallel') {
196
+ let i = 1;
197
+ Object.keys(this.children).forEach(key => {
198
+ let proc = this.children[key];
199
+ if (proc) {
200
+ if (type == 'sequence') {
201
+ setTimeout(()=>{
202
+ proc.kill();
203
+ }, i * 1000)
204
+ i++;
205
+ } else {
206
+ proc.kill();
207
+ }
208
+ }
209
+ });
210
+ }
211
+ }
212
+
213
+ module.exports = ChildPoolJob;
package/jobs/index.js CHANGED
@@ -1,9 +1,9 @@
1
- const ChildJob = require('./child');
2
- const RendererJob = require('./renderer');
3
- const ChildPoolJob = require('./child-pool');
4
-
5
- module.exports = {
6
- ChildJob,
7
- RendererJob,
8
- ChildPoolJob
1
+ const ChildJob = require('./child');
2
+ const RendererJob = require('./renderer');
3
+ const ChildPoolJob = require('./child-pool');
4
+
5
+ module.exports = {
6
+ ChildJob,
7
+ RendererJob,
8
+ ChildPoolJob
9
9
  };
@@ -1,12 +1,12 @@
1
- const Consts = require("../consts");
2
-
3
- module.exports = {
4
- [Consts.polling]: require('./polling'),
5
- [Consts.weights]: require('./weights'),
6
- [Consts.random]: require('./random'),
7
- [Consts.specify]: require('./specify'),
8
- [Consts.minimumConnection]: require('./minimumConnection'),
9
- [Consts.weightsPolling]: require('./weightsPolling'),
10
- [Consts.weightsRandom]: require('./weightsRandom'),
11
- [Consts.weightsMinimumConnection]: require('./weightsMinimumConnection'),
1
+ const Consts = require("../consts");
2
+
3
+ module.exports = {
4
+ [Consts.polling]: require('./polling'),
5
+ [Consts.weights]: require('./weights'),
6
+ [Consts.random]: require('./random'),
7
+ [Consts.specify]: require('./specify'),
8
+ [Consts.minimumConnection]: require('./minimumConnection'),
9
+ [Consts.weightsPolling]: require('./weightsPolling'),
10
+ [Consts.weightsRandom]: require('./weightsRandom'),
11
+ [Consts.weightsMinimumConnection]: require('./weightsMinimumConnection'),
12
12
  };
@@ -1,19 +1,19 @@
1
- /**
2
- * 最小连接数
3
- */
4
- module.exports = function (tasks, conMap={}) {
5
- if (tasks.length < 2) return tasks[0] || null;
6
-
7
- let min = conMap[tasks[0].id];
8
- let minIndex = 0;
9
-
10
- for (let i = 1; i < tasks.length; i++) {
11
- const con = conMap[tasks[i].id] || 0;
12
- if (con <= min) {
13
- min = con;
14
- minIndex = i;
15
- }
16
- }
17
-
18
- return tasks[minIndex] || null;
1
+ /**
2
+ * 最小连接数
3
+ */
4
+ module.exports = function (tasks, conMap={}) {
5
+ if (tasks.length < 2) return tasks[0] || null;
6
+
7
+ let min = conMap[tasks[0].id];
8
+ let minIndex = 0;
9
+
10
+ for (let i = 1; i < tasks.length; i++) {
11
+ const con = conMap[tasks[i].id] || 0;
12
+ if (con <= min) {
13
+ min = con;
14
+ minIndex = i;
15
+ }
16
+ }
17
+
18
+ return tasks[minIndex] || null;
19
19
  };