UNPKG

albertgao.common-electron

Version:

个人常用的nodejs/electron模块

262 lines (255 loc) 7.51 kB
const CP = require('child_process') const Path = require('path') const { nanoid } = require('nanoid') const _ = require('lodash') const vue = require('vue') /** * * @returns {number}在nodejs或者js中返回Cpu数量 */ function cpus() { try { return Math.max(1, require('os').cpus().length) } catch (error) { return Math.max(1, navigator.hardwareConcurrency) } } /** * 用子进程写入csv * * @param {string}path 文件路径 * @param {object[]}rows (可选)首次导入的数据 * @returns {object} .worker worker, setTitles(titles: string[]) 标题 */ function csvAcc(path, rows) { const worker = CP.fork(Path.join(__dirname, './csv-Accumulator.js')) worker.setMaxListeners(Infinity) worker.send({ path }) const work = { worker, setTitles(titles) { worker.send({ titles }) }, push(...lines) { return new Promise((resolve) => { const id = nanoid() worker.on( 'message', ({ complete, id: idCheck }) => complete && idCheck === id && resolve() ) worker.send({ lines, id }) }) }, terminate: () => worker.kill(2), kill: () => worker.kill(2) } rows && work.push(...rows) return work } /** * @param {string}path 路径 * @param {*}obj (可选)可以转为json的内容 * @returns {object} {worker,kill,terminate,write} */ function jsonWriter(path, obj) { const Path = require('path') const worker = CP.fork(Path.join(__dirname, './json-Writer.js')) worker.setMaxListeners(Infinity) worker.send({ path }) const work = { worker: worker, kill: () => worker.kill(2), terminate: () => worker.kill(2), write: (...args) => new Promise((resolve) => { const id = nanoid() worker.on( 'message', ({ complete, id: id1 }) => id1 === id && complete && resolve() ) let postMsg = { path: _.find(args, (e) => /string/i.test(Object.prototype.toString.call(e)) ), json: _.find( args, (e) => !/string/i.test(Object.prototype.toString.call(e)) ), id } worker.send(postMsg) postMsg = null // 释放内存 }) } obj && work.write(obj) work.output = work.write return work } /** * @param {string}path 路径 * @param {object[] | Array[String[]]}data * * @returns {object} {worker,kill,terminate,write} */ function xlsxWriter(path, data) { const Path = require('path') const worker = CP.fork(Path.join(__dirname, 'xlsx-Writer.js')) worker.setMaxListeners(Infinity) worker.send({ path }) const work = { worker: worker, kill: () => worker.kill(2), terminate: () => worker.kill(2), write: (...args) => new Promise((resolve) => { const id = nanoid() worker.on( 'message', ({ complete, id: id1 }) => id1 === id && complete && resolve() ) let postMsg = { path: _.find(args, (e) => /string/i.test(Object.prototype.toString.call(e)) ), json: _.find( args, (e) => !/string/i.test(Object.prototype.toString.call(e)) ), id } worker.send(postMsg) postMsg = null // 释放内存 }) } data && work.write(data) work.output = work.write return work } /** * 创建一个json写入线程 * * @param {string}path 要导出的json文件路径 * @param {*[] | object}rows 首次要导入的数据 * @returns {object}返回{worker,kill,terminate,assign} */ function jsonAcc(path, rows) { const { nanoid } = require('nanoid') const cp = require('child_process') const Path = require('path') const worker = cp.fork(Path.join(__dirname, './json-Accumulator.js')) worker.setMaxListeners(Infinity) path && worker.send({ path }) const work = { worker: worker, kill: () => worker.kill(2), terminate: () => worker.kill(2), assign: (...args) => new Promise((resolve) => { const id = nanoid() worker.on('message', ({ id: id1 }) => id1 === id && resolve()) // 向worker推送rows // let postMsg = { path, rows, id } let postMsg = { path: _.find(args, (e) => /string/i.test(Object.prototype.toString.call(e)) ), rows: _.find( args, (e) => !/string/i.test(Object.prototype.toString.call(e)) ), id } worker.send(postMsg) postMsg = null // 释放内存 }) } rows && work.assign(rows) work.push = work.append = work.assign return work } /** * 对任务进行最优化队列 * * @param {object[]}tasks 任务队列 * @param {Function}tasks.func 该任务所用函数,返回值必须是Promise * @param {*[]}tasks.args 该任务所用函数的参数 * @param {string | null}tasks.key 该任务的返回值如果是Object, 其中有一个key是Promise的话,key的名称 * @param {Function}tasks.then 回调该任务返回值[key]的promise * @param {Function}[watcher=console.log] 回调{waiting, finished, processing, total} * @param {number}[maxChunk=cpus()] 队列最大长度,默认为cpu数量 * @returns {Promise<*[]>} 返回运行结果数组 */ function queque(tasks = [], watcher = console.log, maxChunk = cpus()) { return new Promise((resolve) => { const beforeProcessing = vue.reactive( // 未开始的任务 [...tasks].map((obj, index) => { obj.id = nanoid() obj.index = index return obj }) ) const total = tasks.length const processing = vue.reactive([]) // 执行中的任务 const results = vue.reactive([]) const finished = vue.computed( () => total - processing.length - beforeProcessing.length ) const progress = vue.computed( () => `${~~((finished.value * 1000) / total) / 10}%` ) const detail = vue.computed( () => `${finished.value}/${total} (${progress})` ) vue.watchEffect(() => { watcher && watcher({ waiting: beforeProcessing.length, finished: finished.value, processing: processing.length, progress, detail, total }) }) vue.watchEffect( () => processing.length + beforeProcessing.length === 0 && resolve(results) ) vue.watchEffect(() => { while (processing.length < maxChunk && beforeProcessing.length > 0) { let { func = async () => 0, args = [], key = null, then = () => 0, index } = beforeProcessing.shift() // 提取出waiting的一个元素 const id = nanoid() const job = vue.reactive({ id, promise: key ? func(...args)[key] : func(...args) }) processing.push(job) // 把waiting的最后一个元素充进去 // eslint-disable-next-line promise/catch-or-return job.promise.then((result) => { // 如果该promise已经fulfill _.pullAt( // 删除该元素 processing, _.findIndex(processing, ({ id: idCheck }) => id === idCheck) // 找到一个符合该id的job,然后删除 ) results[index] = result return then(result) // 回调结果 }) args = null // args可能比较大,所以清空内存 } }) }) } module.exports = { csvAcc, queque, jsonAcc, jsonWriter, xlsxWriter }