sync-async-loops
Advanced tools
Comparing version 1.0.0 to 1.1.0
@@ -15,3 +15,3 @@ const Synchronizer = require("..") | ||
const timeout = Math.random() * 10 | ||
await new Promise(resolve => setTimeout(resolve, timeout)); | ||
await new Promise(resolve => setTimeout(resolve, 5)); | ||
return 'result' | ||
@@ -74,8 +74,9 @@ } | ||
resultsArrTwo = [] | ||
const synchronizer = new Synchronizer() | ||
console.warn('\n\n Mapping with synchronization, sleep, and Promise.all') | ||
console.warn('\n\n Mapping with synchronization, sleep, and without Promise.all') | ||
console.time('4') | ||
await Promise.all( | ||
data.map(async (item, index) => { | ||
await new Synchronizer(data, async (synchronizer, item, index) => { | ||
// await Promise.all( | ||
// data.map(async (item, index) => { | ||
resultsArrOne.push(item) | ||
@@ -85,11 +86,30 @@ await synchronizer.runOnce(sleepRandom, 'sleep', 'param1', 'param2') | ||
resultsArrTwo.push(item) | ||
}) | ||
) | ||
console.timeEnd('4') | ||
// }) | ||
// ) | ||
}) | ||
console.timeEnd('4') | ||
testResults(resultsArrOne) | ||
testResults(resultsArrTwo) | ||
resultsArrOne = [] | ||
resultsArrTwo = [] | ||
console.warn('\n\n Mapping with synchronization, sleep, waitAll, and without Promise.all') | ||
console.time('5') | ||
await new Synchronizer(data, async (synchronizer, item, index) => { | ||
resultsArrOne.push(item) | ||
await synchronizer.waitAll(index) // when the callback depends on the resultsArrOne, we have to wait for it to be created completely | ||
await synchronizer.runOnce(sleepRandom, 'sleep', 'param1', 'param2', resultsArrOne) | ||
await synchronizer.sync(index) | ||
resultsArrTwo.push(item) | ||
}) | ||
console.timeEnd('5') | ||
testResults(resultsArrOne) | ||
testResults(resultsArrTwo) | ||
} | ||
populateTheArray() | ||
exampleOne() |
101
index.js
class Synchronizer { | ||
currentStep = 0 | ||
stepsResolvers = [] | ||
data = {} | ||
length = 0 | ||
currentStep = 0 | ||
stepsResolvers = [] | ||
waitAllCount = 0 | ||
waitAllResolver | ||
data = {} | ||
sync (index) { | ||
const promise = new Promise(resolve => this.stepsResolvers[index] = resolve) | ||
this.next() | ||
return promise | ||
} | ||
/** | ||
* the callback will be called by the arr.map() | ||
* | ||
* @Param {Synchronizer} synchronizer - this will be the first param of the callback | ||
* @Param {...any} - the parameters from the map() will follow in the same order as the map() uses them | ||
*/ | ||
/** | ||
* you can use the constructor to avoid writing Promise.all(arr.map()) too many times | ||
* | ||
* @Param {Array<any>} arr - the array that will be used for running a map() loop | ||
* @Param {function} callback - the function that will be called by the map(). | ||
*/ | ||
constructor (arr, callback){ | ||
if (arr) { | ||
this.length = arr.length | ||
} | ||
if (!arr || !callback) { | ||
return | ||
} | ||
return Promise.all(arr.map((...params) => callback(this, ...params))) | ||
} | ||
async next() { | ||
await new Promise(resolve => setTimeout(resolve, 0)); | ||
while(this.stepsResolvers[this.currentStep]) { | ||
this.stepsResolvers[this.currentStep]() | ||
this.currentStep = this.currentStep + 1 | ||
} | ||
} | ||
/** | ||
* will stop the loop untill and will resume them in the order of the index | ||
* | ||
* @Param {number} index - the index that will have to start with 0. | ||
*/ | ||
sync (index) { | ||
const promise = new Promise( resolve => this.stepsResolvers[index] = resolve ) | ||
this.next() | ||
return promise | ||
} | ||
runOnce(callback, name, ...params) { | ||
if (!this.data[name]) { | ||
this.data[name] = callback(...params) | ||
} | ||
return this.data[name] | ||
} | ||
waitAll(index, length) { | ||
if (!length) { | ||
length = this.length | ||
} | ||
this.waitAllCount = this.waitAllCount + 1 | ||
if (this.waitAllCount >= length) { | ||
this.waitAllResolver() | ||
} | ||
if (this.waitAllResolver) { | ||
return this.waitAllResolver | ||
} | ||
const promise = new Promise( resolve => this.waitAllResolver = resolve ) | ||
return this.waitAllResolver | ||
} | ||
/** | ||
* the callback function will be called only once, and runOnce will return the same result/promise for each call | ||
* | ||
* @Param { ...any} - starting with the 3rd param onward, they will be reuseed to call the callback | ||
*/ | ||
/** | ||
* run a function one time and return the same result/promise each other time | ||
* | ||
* @Param {function} callback - the function that will be called one single time | ||
* @Param {string} name - this one the identificator for the callback, and should be uniq for each use | ||
* @Param {...any} - any following params will be used to call the callback | ||
*/ | ||
runOnce(callback, name, ...params) { | ||
if (!this.data[name]) { | ||
this.data[name] = callback(...params) | ||
} | ||
return this.data[name] | ||
} | ||
async next() { | ||
await new Promise(resolve => setTimeout(resolve, 0)); | ||
while(this.stepsResolvers[this.currentStep]) { | ||
this.stepsResolvers[this.currentStep]() | ||
this.currentStep = this.currentStep + 1 | ||
} | ||
} | ||
} | ||
module.exports = Synchronizer | ||
module.exports = Synchronizer |
{ | ||
"name": "sync-async-loops", | ||
"version": "1.0.0", | ||
"version": "1.1.0", | ||
"description": "a tool to help you controll asynchronous loops, speed things up, and make sure certain parts are executed in an orderly fashion while keeping the asynchronous nature of the loop", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
# sync-async-loops | ||
The library purpose is to help you synchronise asynchronous loops in order to obtain a better performance | ||
@@ -10,4 +9,9 @@ | ||
const synchronizer = new Synchronizer() | ||
const synchronizer = new Synchronizer() if you want to use your own Promise.all(data.map()) | ||
await new Synchronizer(data, (synchronizer, item, index, .....) => {}) | ||
- the first argument in the callback is the synchronizer, | ||
- the rest of the arguments are the arguments for the callback from data.map() | ||
## synchronizer.sync(index) | ||
@@ -23,2 +27,8 @@ | ||
## synchronizer.waitAll(index, length?) | ||
- unlike sync, this one waits for all the loops to reach this point before letting them go | ||
- if we use Synchronizer(data, () => {}) instead of Promise.all(data.map()) then we can ommit the length paramter | ||
## Example 1 | ||
@@ -44,13 +54,24 @@ | ||
const projects = [] | ||
await Promise.all( | ||
users.map(async (user, index) => { | ||
userIds.push(user.id) | ||
await synchronizer.sync(index) | ||
const userProjects = await synchronizer.runOnce(findProjectsByUserIds,userIds) | ||
projects = projects.concat(userProjects) | ||
await new Synchronizer( users, async (user, index) => { | ||
userIds.push(user.id) | ||
await synchronizer.waitAll(index) | ||
const userProjects = await synchronizer.runOnce(findProjectsByUserIds, 'getProjectUsers', userIds) | ||
const projectsMap = synchronizer.runOnce(mapProjects, 'mapProjectUsers', userProjects) | ||
const project = projectsMap.get(userId) | ||
projects.push({ | ||
...project, | ||
userFullName: `${user.firstName} ${user.lastName}` | ||
}) | ||
) | ||
}) | ||
return projects | ||
} | ||
const mapProjects (userProjects) => { | ||
const projectsMap = new Map() | ||
for (project of Projects){ | ||
projectsMap.set(project.user.id, project) | ||
} | ||
return projectsMap | ||
} | ||
``` | ||
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
9525
173
75
1