UNPKG

w-data-syncer

Version:

A tool for data detection and synchronization.

399 lines (325 loc) 11.2 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>WDataSyncer.mjs - Documentation</title> <script src="scripts/prettify/prettify.js"></script> <script src="scripts/prettify/lang-css.js"></script> <!--[if lt IE 9]> <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> <![endif]--> <link type="text/css" rel="stylesheet" href="styles/prettify.css"> <link type="text/css" rel="stylesheet" href="styles/jsdoc.css"> <script src="scripts/nav.js" defer></script> <meta name="viewport" content="width=device-width, initial-scale=1.0"> </head> <body> <input type="checkbox" id="nav-trigger" class="nav-trigger" /> <label for="nav-trigger" class="navicon-button x"> <div class="navicon"></div> </label> <label for="nav-trigger" class="overlay"></label> <nav > <h2><a href="index.html">Home</a></h2><h3>Global</h3><ul><li><a href="global.html#WDataSourceFromCsv">WDataSourceFromCsv</a></li><li><a href="global.html#WDataSyncer">WDataSyncer</a></li></ul> </nav> <div id="main"> <h1 class="page-title">WDataSyncer.mjs</h1> <section> <article> <pre class="prettyprint source linenums"><code>import get from 'lodash-es/get.js' import each from 'lodash-es/each.js' import map from 'lodash-es/map.js' import size from 'lodash-es/size.js' import sortBy from 'lodash-es/sortBy.js' import evem from 'wsemi/src/evem.mjs' import genPm from 'wsemi/src/genPm.mjs' import isestr from 'wsemi/src/isestr.mjs' import ispint from 'wsemi/src/ispint.mjs' import isearr from 'wsemi/src/isearr.mjs' import isbol from 'wsemi/src/isbol.mjs' import cint from 'wsemi/src/cint.mjs' import haskey from 'wsemi/src/haskey.mjs' import ltdtDiffByKey from 'wsemi/src/ltdtDiffByKey.mjs' /** * 資料單向同步程序 * @param {Object} src - 資料來源,需提供 select 函數 (async) * @param {Object} tar - 資料目標,需提供 select、insert、save、del 函數 (async) * @param {Object} opt - 設定物件 * @param {String} [opt.key='time'] - 用於排序與比對的 key * @param {Number} [opt.timeInterval=20000] - 同步觸發間隔時間(毫秒),預設每 20 秒執行一次(1 分鐘 3 次) * @param {boolean} [opt.useShowLog=false] - 是否顯示 log 資訊 * @returns {EventEmitter} */ function WDataSyncer(src, tar, opt = {}) { //key let key = get(opt, 'key') if (!isestr(key)) { key = 'time' } //timeInterval let timeInterval = get(opt, 'timeInterval') if (!ispint(timeInterval)) { timeInterval = 20000 } timeInterval = cint(timeInterval) //waitEmitInsert let waitEmitInsert = get(opt, 'waitEmitInsert') if (!isbol(waitEmitInsert)) { waitEmitInsert = false } //waitEmitSave let waitEmitSave = get(opt, 'waitEmitSave') if (!isbol(waitEmitSave)) { waitEmitSave = false } //waitDel let waitDel = get(opt, 'waitDel') if (!isbol(waitDel)) { waitDel = false } //waitEmitChange let waitEmitChange = get(opt, 'waitEmitChange') if (!isbol(waitEmitChange)) { waitEmitChange = false } //waitEmitChangeAll let waitEmitChangeAll = get(opt, 'waitEmitChangeAll') if (!isbol(waitEmitChangeAll)) { waitEmitChangeAll = false } //useShowLog let useShowLog = get(opt, 'useShowLog') if (!isbol(useShowLog)) { useShowLog = false } //ev let ev = evem() //compareAndSync let compareAndSync = async () => { try { //ltdtSrc if (useShowLog) { console.log(`src select...`) } let ltdtSrc = await src.select() if (useShowLog) { console.log(`src select done`) } // console.log('ltdtSrc', ltdtSrc) //check if (!isearr(ltdtSrc)) { if (useShowLog) { console.log(`no src, skip and waiting...`) } return } //ltdtTar if (useShowLog) { console.log(`tar select...`) } let ltdtTar = await tar.select() if (useShowLog) { console.log(`tar select done`) } // console.log('ltdtTar', ltdtTar) //check if (size(ltdtSrc) &lt; size(ltdtTar)) { if (useShowLog) { console.log(`numSrc[${size(ltdtSrc)}] &lt; numTar[${size(ltdtTar)}], skip and waiting...`) } return } if (useShowLog) { console.log(`size(ltdtSrc)`, size(ltdtSrc)) console.log(`size(ltdtTar)`, size(ltdtTar)) } //sortBy if (useShowLog) { console.log('sortBy...') } ltdtSrc = sortBy(ltdtSrc, key) ltdtTar = sortBy(ltdtTar, key) if (useShowLog) { console.log('sortBy done') } //排序與建立map比對 if (useShowLog) { console.log('ltdtDiffByKey...') } let r = ltdtDiffByKey(ltdtTar, ltdtSrc, key, { withInfor: false }) if (useShowLog) { console.log('ltdtDiffByKey done') } // console.log('r', r) let nAdd = size(r.add) let nDiff = size(r.diff) let nDel = size(r.del) if (useShowLog) { console.log('operate and emit...') } if (nAdd > 0) { if (useShowLog) { console.log('r.add', map(r.add, key), nAdd) } await tar.insert(r.add) if (waitEmitInsert) { let pm = genPm() ev.emit('insert', r.add, pm) await pm .catch(() => {}) } else { ev.emit('insert', r.add) } if (waitEmitChange) { let pm = genPm() ev.emit('change', { type: 'insert', items: r.add }, pm) await pm .catch(() => {}) } else { ev.emit('change', { type: 'insert', items: r.add }) } } if (nDiff > 0) { if (useShowLog) { console.log('r.diff', map(r.diff, key), nDiff) } await tar.save(r.diff) if (waitEmitSave) { let pm = genPm() ev.emit('save', r.diff, pm) await pm .catch(() => {}) } else { ev.emit('save', r.diff) } if (waitEmitChange) { let pm = genPm() ev.emit('change', { type: 'save', items: r.diff }, pm) await pm .catch(() => {}) } else { ev.emit('change', { type: 'save', items: r.diff }) } } if (nDel > 0) { if (useShowLog) { console.log('r.del', map(r.del, key), nDel) } await tar.del(r.del) if (waitDel) { let pm = genPm() ev.emit('del', r.del, pm) await pm .catch(() => {}) } else { ev.emit('del', r.del) } if (waitEmitChange) { let pm = genPm() ev.emit('change', { type: 'del', items: r.del }, pm) await pm .catch(() => {}) } else { ev.emit('change', { type: 'del', items: r.del }) } } if ((nAdd + nDiff + nDel) > 0) { //更改type if (true) { let kp = { add: 'insert', diff: 'save', del: 'del', same: 'same', } let _r = {} each(r, (ltdt, type) => { if (haskey(kp, type)) { type = kp[type] } else { console.log('kp', kp) throw new Error(`invalid type[${type}]`) } _r[type] = ltdt }) r = _r } if (waitEmitChangeAll) { let pm = genPm() ev.emit('change-all', r, pm) await pm .catch(() => {}) } else { ev.emit('change-all', r) } } if (useShowLog) { console.log('operate and emit done') } } catch (err) { if (useShowLog) { console.log(err) } ev.emit('error', err) } } //timer let lock = false let timer = setInterval(() => { //check if (lock) { if (useShowLog) { console.log('locking...') } return } lock = true //compareAndSync if (useShowLog) { console.log('compareAndSync...') } compareAndSync() .catch((err) => { if (useShowLog) { console.log(err) } ev.emit('error', err) }) .finally(() => { if (useShowLog) { console.log('compareAndSync done') } lock = false }) }, timeInterval) //clear let clear = () => { clearInterval(timer) } //save ev.clear = clear return ev } export default WDataSyncer </code></pre> </article> </section> </div> <br class="clear"> <footer> Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.4</a> on Sat Jul 05 2025 15:28:53 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme. </footer> <script>prettyPrint();</script> <script src="scripts/polyfill.js"></script> <script src="scripts/linenumber.js"></script> </body> </html>