UNPKG

array-chunk-reader

Version:

Module for reading array by chunks using promise

158 lines (128 loc) 4.09 kB
(function () { "use strict"; class ArrayChunkReader { constructor(array, options) { if(!Array.isArray(array)) { throw new Error('You have to pass an array'); } options = options || {}; this.array = array; this.arrayLength = array.length; this.startFrom = options.startFrom || options.from || 0; this.startTo = options.readTo || options.to || this.arrayLength; if (this.startFrom > array.length) { this.startFrom = length; } if(this.startTo < this.startFrom) { throw new Error('Wrong range for reading'); } this.currentFrom = this.startFrom; this.currentTo = this.startTo; const defaults = { size: Math.floor(Math.sqrt(this.arrayLength)), timeout: 1, log: true }; this.options = Object.assign(defaults, options || {}); } getCurrentChunkSize() { const diff = this.currentTo - this.currentFrom; if(diff < this.options.size) { return diff; } return this.options.size; } chunk(lastInfo, fn, fnChunk, callback) { lastInfo = lastInfo || {}; let startChunk = Date.now(); let length = this.startTo; let start = this.startFrom; const info = { iteration: (lastInfo.iteration || 0) + 1, length: length, from: lastInfo.to || start, }; info.to = info.from + this.options.size; if (info.needTime < 0) { info.needTime = 0; } if (info.to > length) { info.to = length; } if (info.from >= length || this.__stopped) { let result = {}; result.avgChunkTime = lastInfo.avgTime || 0; result.chunkCount = lastInfo.iteration || 0; this.__stopped && this.options.log && console.log("Array chunk reader has been stopped"); return callback(null, info, result); } this.currentFrom = info.from; this.currentTo = info.to; let promise = []; for (let i = info.from; i < info.to; i++) { try { promise.push(fn(this.array[i], info, lastInfo)); } catch (err) { return callback(err); } } Promise.all(promise).then((data) => { if(!this.__stopped && fnChunk) { return fnChunk(data); } }).then(() => { let realLength = length - start; promise = null; info.time = Date.now() - startChunk; info.pastTime = (lastInfo.pastTime || 0) + info.time; info.avgTime = Math.floor(info.pastTime / info.iteration); info.needTime = Math.floor(realLength * info.avgTime / this.options.size) - info.pastTime; callback(null, info); }).catch(callback); } start(fn, fnChunk) { let start = Date.now(); const next = (lastInfo, fn, fnChunk, callback) => { this.chunk(lastInfo, fn, fnChunk, (err, info, result) => { if (err) { return callback(err); } else if (result) { result.time = Date.now() - start; return callback(null, result); } if (this.options.log) { console.log("chunk:", JSON.stringify(info, undefined, 1)); } if (this.options.timeout == 0) { return next(info, fn, fnChunk, callback); } setTimeout(() => { next(info, fn, fnChunk, callback); }, this.options.timeout); }); }; return new Promise((res, rej) => { next(null, fn, fnChunk, (err, result) => { if (err) { return rej(err); } else if (result) { return res(result); } rej(new Error("Array chunk reader is failed")); }); }); } stop() { this.__stopped = true; } } if (typeof module == "object" && typeof module.exports == "object") { module.exports = ArrayChunkReader; } else if (typeof window == "object") { window.ArrayChunkReader = ArrayChunkReader; } })();