One function inside parent function wont run asynchronously - javascript

Apologies for being unable to provide working code but, perhaps foolishly, I have a world of functions calling functions and also two calls to an external astar path finder script. I have been moving instances of await, .then and resolve about for days and days now and I just can't get movePlayer(journeyPart2) to wait until await movePlayer(journeyPart1) has completed. I've watched countless videos about promises as well but I can't see where I'm going wrong. I also tried only returning something once the for loop reaches its last instance but this didn't work. I'm really hoping that it is obvious to someone where I'm going wrong. Unfortunately the second movePlayer function takes a variable amount of time to complete, so I can't use a set interval alone to queue the second movePlayer function.
I don't actually need any data to be returned from the movePlayer functions but I understand at least the promise must be returned. How can I make the second movePlayer function wait?
Edit: Note that the else if works fine as movePlayer is only called once.
function movePlayer(journey) {
return new Promise((resolve, reject) => {
for (let i = 0; i < journey.length; i++){
(function(i){
window.setTimeout(function(){
let nextX = journey[i].y;//?SWITCHED X AND Y AS ASTAR SWITCHES IN GRAPH
let nextY = journey[i].x;//?SWITCHED X AND Y AS ASTAR SWITCHES IN GRAPH
let fromTop = (26 + (nextX * 16) + (nextY * 16)) + "px";
let fromLeft = (576 + (nextX * 32) - (nextY * 32)) + "px";
document.getElementById("playerLayer").style.left = fromLeft;
document.getElementById("playerLayer").style.top = fromTop;
}, i * (900));
}(i));
}
resolve("complete")
reject("failure")
})
}
function globalPathFindANDMove(cellNumEnd, levelNumEnd) {
let cellNumStart = playerInfo.cellNow;
let levelNumStart = playerInfo.levelNow;
let j1Complete = false;
if (levelNumStart != levelNumEnd) {
(async function(){
try {
let journeyPart1 = await localPathFind(cellNumStart, undefined, levelNumStart)
let journeyPart2 = await localPathFind(undefined, cellNumEnd, levelNumEnd)
let useless = await movePlayer(journeyPart1)
console.log(useless)
movePlayer(journeyPart2)//this function won't wait until the function above completes
//------------------------------------------------------changePlayerLevel (levelNumEnd);-----------------------CREATE LATER
} catch (err) {
}
})();
} else if (levelNumStart == levelNumEnd) {
let journey = localPathFind(cellNumStart, cellNumEnd, levelNumEnd);
movePlayer(journey);
}
}

It's hard to tell for sure what you are trying to do in your code, but I think you just want to wait until the setTimeout part has run before resolving:
function movePlayer(journey) {
return new Promise((resolve, reject) => {
for (let i = 0; i < journey.length; i++){
(function(i){
window.setTimeout(function(){
let nextX = journey[i].y;//?SWITCHED X AND Y AS ASTAR SWITCHES IN GRAPH
let nextY = journey[i].x;//?SWITCHED X AND Y AS ASTAR SWITCHES IN GRAPH
let fromTop = (26 + (nextX * 16) + (nextY * 16)) + "px";
let fromLeft = (576 + (nextX * 32) - (nextY * 32)) + "px";
document.getElementById("playerLayer").style.left = fromLeft;
document.getElementById("playerLayer").style.top = fromTop;
if (i === journey.length - 1) {
resolve("complete")
}
}, i * (900));
}(i));
}
})
}

Related

Is there a "repeat [function] until [property = true]" type of loop in MakeCode JS?

I'm making a game in Microsoft MakeCode Arcade for a school project, and I wanted to know if there was a "repeat [function] until [property = true]" type of loop like there is in Luau. I wanted to use this so that the game waits until my player sprite is at a certain coordinate to run some code. I figured out a way to do this in a different way, but I wanted to know just for future reference.
If anyone is wondering, this is what the alternative way I am using.
game.onUpdateInterval(100, function () {
if (level == 1) {
if (myPlayer.x == 950 && myPlayer.y == 140) {
myPlayer.y = 100
myPlayer.x = 10
if (game.ask("Does " + level_1 + " + " + level1_2 + " = " + level1CorrectAns + "?")) {
console.log("Level 1 Completed successfully")
level += 1
LevelChange()
} else {
game.over(false)
}
}
}
})
You could use either while loop or do...while loop
For while loop, the following code will keep on running as long as the condition is true.
let x = 0
while (x < 3) {
x++
}
console.log(x) // print 3
For do...while loop, the following code will keep on running as long as the condition is true. And this loop will run at least once.
let result = '';
let x = 0;
do {
x = x + 1;
result = result + x;
} while (x < 5);
console.log(result); // print "12345"
Coming back to your example, I believe you're running the loop every 100ms (based on first argument of your game.onUpdateInterval.
You could easily do this by adding a timer function and wrap this loop in as an async function.
const timer = ms => new Promise(res => setTimeout(res, ms))
async function updateInterval() {
while () {
// Your logic here
await timer(100) // You can change the timeout to your desired ms
}
}
updateInterval();
While I'm not 100% sure of the functionality of your current workaround, but this is my interpretation (Hope it works)
const timer = (ms) => new Promise((res) => setTimeout(res, ms));
async function updateInterval() {
let state = true; // This is just a condition if the loop should continue
while (state) {
if (level == 1) {
if (myPlayer.x == 950 && myPlayer.y == 140) {
myPlayer.y = 100;
myPlayer.x = 10;
if (
game.ask(
'Does ' +
level_1 +
' + ' +
level1_2 +
' = ' +
level1CorrectAns +
'?'
)
) {
console.log('Level 1 Completed successfully');
level += 1;
LevelChange();
state = false; // Update the state to false, so it will exit the while loop
} else {
game.over(false);
}
}
}
await timer(100); // You can change the timeout to your desired ms
}
}
updateInterval();

How to reduce number of computations during d3.js transition?

So right now, I'm trying to implement a search bar function into my d3.js plot. Right now it doesn't do anything, but that's not the issue at the moment. The problem is that when I type/delete something from the bar, there's visible lag/choppiness in the characters appearing/disappearing. I believe the issue is stemming from my plot. I have 140+ dots moving around the screen, and their position is being interpolated. So from the beginning to the end of the transition, my code has to compute 140 positions thousands of times over.
I've looked into trying to reduce the cardinality of the d3.interpolateNumber function, but it appears that there isn't a third argument to change the number of terms like in a linspace command. Right now I have an array of 1000 numbers for my function to run through, but I don't know how to pass the array to my other functions.
Below are the pertinent functions for this issue. The commented line in tweenPatch is the original code I had that made my code run, but gave my plot computational issues. Variables arr, curr, and step were my attempt to fix the situation, but I haven't been able to figure out how to pass the array into displayPatch().
function tweenPatch() {
var patch = d3.interpolateNumber(1, 26);
var arr = [];
var curr = 1;
var step = (26 - 1) / (1000 - 1);
for (var i = 0; i < 1000; i++) {
arr.push(curr + (step * i));
}
return arr.forEach(function(d) {
console.log(arr[d]);
displayPatch(arr[d]);
});
//return function(t) { displayPatch(t); };
}
function displayPatch(patch) {
dots.data(interpolateData(patch), function(d) { return d.name; }).call(position).sort(order);
var inter = Math.floor(patch);
var seas = 8;
var patc = 1;
if (inter > 24) {
seas = 9;
patc = inter - 24;
} else {
patc = inter;
}
label.text("Patch " + seas + "." + patc);
}
function interpolateValues(values, number) {
old = Math.floor(number);
upd = Math.ceil(number);
var old_data = values.filter(function(d) {return d.internal == old;});
var new_data = values.filter(function(d) {return d.internal == upd;});
var oobj = old_data[0];
var nobj = new_data[0];
var onum = oobj[Object.keys(oobj)[4]];
var nnum = nobj[Object.keys(nobj)[4]];
var difint = number - old;
var difdis = 0;
var newnum = nnum;
if (nnum > onum) {
difdis = nnum - onum;
newnum = ((difint) * difdis) + onum;
} else if (onum > nnum) {
difdis = onum - nnum;
newnum = onum - ((difint) * difdis);
}
return newnum;
}
I believe switching my SVG to a canvas may help things, but since I have no knowledge of canvas I'd rather leave that as a last resort.

Running a jQuery function multiple times sequentially (for a Bookmarklet)

I've got the following jQuery code which I use in a Bookmarklet. It clicks on all the buttons on the page (with the class "Unfollow") one by one, with a random time between each one...
javascript: (function() {
var unfollowButtons = $('button.Unfollow');
var index = unfollowButtons.length - 1;
unfollow();
function unfollow() {
if (index >= 0) {
$(unfollowButtons[index--])
.click();
setTimeout(unfollow, Math.floor((Math.random() * 1000) + 500));
}
}
})();
I'd like to run the above function again twice once it has completed its cycle.
Just running the function again causes that to run in parallel with the first function call.
How do I run the unfollow() function 2 or 3 times without them all running in parallel?
Try it this way (using ES6 Promises):
var runUnfollow = function() {
return new Promise(function(resolve, reject){
var index = unfollowButtons.length - 1;
// fencepost for the loop
var p = Promise.resolve();
// we stop execution at `i == 0`
for (var i = index; i >= 0; i--) {
// run the promise
// then set `p` as the next one
p = p.then(unfollowTimeout.bind(null, i));
}
// make sure we run the last execution at `i == 0`.
p.then(function(){
resolve();
})
function unfollowTimeout(i){
// return a promise to run `unfollow` and a `setTimeout`
return new Promise(function(resolve,reject){
unfollow(i);
setTimeout(resolve, Math.floor((Math.random() * 1000) + 500));
})
}
function unfollow(i) {
$(unfollowButtons[i])
.click();
}
})
}
// run three times synchronously
runUnfollow().then(runUnfollow).then(runUnfollow).then(function(){
//finished
});
// another way to run three times synchronously
p = runUnfollow();
for(i=3; i > 0; i--){
p = p.then(runUnfollow);
}
p.then(function(){
//finished
});
// run in parallel
Promise.all([runUnfollow, runUnfollow, runUnfollow])
.then(function(){
//finished
});
EDIT: Went back and read your question again, realized you were trying to run everything multiple times. I've edited to reflect that.
Just reset index and restart after each button is clicked:
javascript: (function() {
var unfollowButtons = $('button.Unfollow');
var index = unfollowButtons.length - 1;
var totalRuns = 3;
unfollow();
function unfollow() {
if (index < 0 && totalRuns) {
totalRuns--;
unfollowButtons = $('button.Unfollow');
index = unfollowButtons.length - 1;
}
if (index >= 0) {
$(unfollowButtons[index--])
.click();
setTimeout(unfollow, Math.floor((Math.random() * 1000) + 500));
}
}
})();
You should look at Promises.
Resolve your Promise at your function's execution's very end and call your function again. You should be good with that.
In your specific case, you could simply build an array which contains twice each button :
// turn the jQuery selection into a regular array :
var unfollowButtons = $('button.Unfollow').get();
// build a new array, which contains two copies of the above selection :
unfollowButtons = unfollowButtons.concat(unfollowButtons);
You have 2 options
1.Use a User Script
For that, you need a User Script extension manager, for example Tampermonkey for Chrome, Greasemonkey for Firefox, etc.
But since you want a bookmarklet, just leave it.
2.Modify the Bookmarklet a little as follows
Add this code inside the unfollow function
That is check whether index reached 0 and also the flag is set or not.
FLAG is important otherwise it will create a infinitive recursion loop.
First set FLAG to 0 outside of unfollow function.
Then in unfollow function, if the FLAG is 0 and index is 0, initiate the next iteration and Set FLAG to 1.
if(index < 0 && FLAG==0){
var unfollowButtons = $('button.Unfollow');
FLAG=1;
var index = unfollowButtons.length - 1;
unfollow();
}
So, it will look like this.
javascript: (function() {
var unfollowButtons = $('button.Unfollow');
var index = unfollowButtons.length - 1;
var FLAG=0;
unfollow();
function unfollow() {
if (index >= 0) {
$(unfollowButtons[index--])
.click();
if(index < 0 && FLAG==0){
unfollowButtons = $('button.Unfollow');
FLAG=1;
index = unfollowButtons.length - 1;
unfollow();
}
setTimeout(unfollow, Math.floor((Math.random() * 1000) + 500));
}
}
})();
If you want to do it totally 3 times, change if(index < 0 && FLAG<=2){ and FLAG=1 to FLAG +=1
As i understand your requirements it can be done like this :
javascript: (function() {
var unfollowButtons = $('button.Unfollow');
var index = unfollowButtons.length - 1;
unfollow();
var runForNoOfTime = 3;
var runningForTime = 1;
function unfollow() {
if (index >= 0) {
$(unfollowButtons[index--]).click();
setTimeout(unfollow, Math.floor(Math.random() * 1000) + 500));
}else if(runningForTime < runForNoOfTime){
runningForTime++;
unfollowButtons = $('button.Unfollow'); //if buttons with class 'Unfollow' changes.
index = unfollowButtons.length - 1;
setTimeout(unfollow, Math.floor(Math.random() * 1000) + 500));
}
}
})();
You can use recursion to achieve the desired effect of running your function multiple times sequentially. Here's how this can be done:
(function() {
var unfollowButtons = $('button.Unfollow');
var index = unfollowButtons.length - 1;
function unfollow(callback) {
if (index >= 0) {
$(unfollowButtons[index--]).click();
}
callback();
}
function handleUnfollow(maxIter, iter) {
iter = typeof iter === "number" ? iter : 0;
if ( iter >= maxIter ) {
// base case reached, stop further recursive calls
return true;
}
// call unfollow once
unfollow(function() {
setTimeout(function() {
// recursive call
handleUnfollow(maxIter, ++iter);
}, Math.floor((Math.random() * 1000) + 500));
});
}
// execute recursive function, which will iterate 2 times
handleUnfollow(2);
})();
As far as I'm aware Javascript runs on a single thread, so there is no actual parallel processing taking place.
If you just simply want the function to run itself x times then use recursion:
function DoSomething(steps) {
// Do stuff here
steps--;
if (steps <== 0) {
return;
}
DoSomething(steps);
}
If you want things to run in "parallel" with Javascript then perhaps you could look into having some external code that manages threads and executes multiple Javascript processes in parallel (although I'm not sure if this is possible, and, if it is, whether you'll be able to have the scripts accessing the same data at the same time or talking to eachother).
I have made the current code as block and added wrapper logic. Check if this works.
(function() {
var iterations = 2;
unfollowBlock();
function unFollowBlock() {
if (iterations-- >0) {
var unfollowButtons = $('button.Unfollow');
var index = unfollowButtons.length - 1;
unfollow();
function unfollow() {
if (index >= 0) {
$(unfollowButtons[index--])
.click();
setTimeout(unfollow, Math.floor((Math.random() * 1000) + 500));
}
else { //index=-1 end of unfollowblock
setTimeout(unFollowBlock, Math.floor((Math.random() * 1000) + 500));
}
}
}
}
})();
Declare a flag/check variable eg. var isCycleComplete;
var isCycleComplete = false;
if(isCycleComplete){ // if true runs unfollow function twice
unfollow();
unfollow();
isCycleComplete = false; // resets flag
}
else{ // if false
unfollow();
isCycleComplete = true; //sets flag to true
}
M not a pro at javascript but See if this simple snippet helps you.

Javascript, calling asynchronous function in a for loop [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 5 years ago.
I wish to call an asynchronous function in a for loop. I am having significant trouble doing so and am getting a variety of errors such as undefined variables and such.
Evaluator.prototype.asyncEval = function(predictor) {
let self = this;
let metric = 0; //METRICS SHOULD BE UPDATED BY ASYNC FUNCTION
for (let i = 1; i < this.fullTraces.length; i++) {
(function(index){
let deltaTime = self.fullTraces[i][2] - this.fullTraces[i-1][2];
let subTraces = self.fullTraces.slice(0, i);
predictor.predict(subTraces, (dist) => { // ASYNC FUNCTION
if (dist !== null) {
let result = dist.getTopK(1);
let pX = result[0][0][0];
let pY = result[0][0][1];
let x = self.fullTraces[i][0];
let y = self.fullTraces[i][1];
let a = pX - x;
let b = pY - y;
metric += Math.sqrt(a*a + b*b);
}
});
}(i));
}
metric /= this.fullTraces.length - 1;
return metric;
}
My asynchronous function predictor.predict() is actually using a POST request to get results from my web server.
YourPredictor.prototype.predict = function(trace, callback) {
return asyncPostRequest('https://0.0.0.0:5000/prediction', trace, responseText => {
prediction = JSON.parse(responseText);
let pred = [prediction['xs'], prediction['ys'], 'm'];
let dist = Dist.NaiveDistribution.from(pred, mouseToKey);
dist.set(pred, 1);
callback(dist);
});
}
How can I get this to work? I am running this on Chrome. I know there is the new await and async from ES7, but I don't want to use something that bleeding edge yet.
You need to refactor the code to replace the loop with a self-invoking loop, so that each time the asynchronousis called, the result from it is handed back, then iteration is checked, if i
Since the main code is asynchronous you will also need a callback for the initial call function (the doneCallback below).
Example
I left in the original code where it is expected to work, but made a couple of changes for it to work here.
function Evaluator() {}; // dummy for test
Evaluator.prototype.asyncEval = function(predictor, doneCallback) {
let self = this;
let metric = 0;
let length = 10; //this.fullTraces.length;
let i = 1;
// replaces for-loop
(function loop() {
self.predict(0, (dist) => {
// ...
metric += dist;
if (++i < length) loop();
else {
// ...
doneCallback(metric);
}
});
})();
}
// note: I changed prototype parent in this example
Evaluator.prototype.predict = function(trace, callback) {
//...
setTimeout(callback, 100, Math.random() * 100); // simulate async call
}
// TEST
var test = new Evaluator();
test.asyncEval(0, function(result) {
document.querySelector("div").innerHTML = result;
});
<div>Calcing...</div>
Example leaving the original code in place at the intended locations:
function Evaluator() {}; // dummy for test
Evaluator.prototype.asyncEval = function(predictor, doneCallback) {
let self = this;
let metric = 0; //METRICS SHOULD BE UPDATED BY ASYNC FUNCTION
let length = 10; //this.fullTraces.length;
let i = 1;
// replaces for-loop
(function loop() {
//let deltaTime = self.fullTraces[i][2] - this.fullTraces[i - 1][2];
//let subTraces = self.fullTraces.slice(0, i);
self.predict(0, (dist) => { // ASYNC FUNCTION
//predictor.predict(subTraces, (dist) => { // ASYNC FUNCTION
/*if (dist !== null) {
let result = dist.getTopK(1);
let pX = result[0][0][0];
let pY = result[0][0][1];
let x = self.fullTraces[i][0];
let y = self.fullTraces[i][1];
let a = pX - x;
let b = pY - y;
metric += Math.sqrt(a * a + b * b);
}*/
metric += dist;
if (++i < length) loop();
else {
//metric /= this.fullTraces.length - 1;
//return metric; <- don't use, instead use:
doneCallback(metric);
}
});
})();
}
// note: I changed prototype parent in this example
Evaluator.prototype.predict = function(trace, callback) {
setTimeout(callback, 100, Math.random() * 100); // simulate async call
/*return asyncPostRequest('https://0.0.0.0:5000/prediction', trace, responseText => {
prediction = JSON.parse(responseText);
let pred = [prediction['xs'], prediction['ys'], 'm'];
let dist = Dist.NaiveDistribution.from(pred, mouseToKey);
dist.set(pred, 1);
callback(dist);
});*/
}
// TEST
var test = new Evaluator();
test.asyncEval(0, function(result) {
document.querySelector("div").innerHTML = result;
});
<div>Calcing...</div>
If you dont want to use async + await combination, I would suggest to take a look at this post.
Asynchronous for cycle in JavaScript
I'm using this asyncLoop function and it's working great:
The function takes three arguments: 1) iterations, 2) a loop callback function and 3) Done callback function,
Check out the code:
function promise1(param){
return new Promise((resolve, reject) => setTimeout(() => { resolve(`Promise1 ${param} Done`)}, 2000))
}
function asyncLoop(iterations, func, callback) {
var index = 0;
var done = false;
var loop = {
next: function() {
if (done) {
return;
}
if (index < iterations) {
index++;
func(loop);
} else {
done = true;
callback();
}
},
iteration: function() {
return index - 1;
},
break: function() {
done = true;
callback();
}
};
loop.next();
return loop;
}
var asyncProc = ["Process1", "Process2", "Process3"]
asyncLoop
(
asyncProc.length,
(loop) => { promise1(asyncProc[loop.iteration()]).then((msg) =>{ console.log(msg); loop.next() }) },
() => { console.log("ALL DONE!")});
You cannot return the value of the "metric" synchronously if it is being modified asynchronously. You'll need to pass a callback into your method so the "metric" can be returned when it is ready.
Evaluator.prototype.asyncEval = function (predictor, callback) {
let self = this;
let metric = 0; //METRICS SHOULD BE UPDATED BY ASYNC FUNCTION
let callbacks = 0; // Keep a counter for the asynchronous callbacks
for (let i = 1; i < self.fullTraces.length; i++) {
let deltaTime = self.fullTraces[i][2] - this.fullTraces[i - 1][2];
let subTraces = self.fullTraces.slice(0, i);
// Queue up an asynchronous callback
predictor.predict(subTraces, (dist) => { // ASYNC FUNCTION
if (dist !== null) {
let result = dist.getTopK(1);
let pX = result[0][0][0];
let pY = result[0][0][1];
let x = self.fullTraces[i][0];
let y = self.fullTraces[i][1];
let a = pX - x;
let b = pY - y;
metric += Math.sqrt(a * a + b * b);
}
// Decrement the counter and check if we're done
if (--callbacks === 0) {
callback(metric / (self.fullTraces.length - 1));
}
});
// Increment the counter
callbacks++;
}
};

promise change global variable in for loop

I am trying to do some benchmarking on different style of javascript code, here is what I have:
var Promise = require('bluebird');
var timer = function(name) {
var start = new Date();
return {
stop: function() {
var end = new Date();
var time = end.getTime() - start.getTime();
console.log('Function:', name, 'finished in', time, 'ms');
}
};
};
function regular (a, cb) {
if (a % 2 === 0) return cb(null, a);
return cb(a);
}
function promise (a) {
return new Promise (function (resolve, reject) {
if (a % 2 === 0) resolve(a);
else reject(a);
});
}
var t = timer('regular');
var g = 0;
for (var i = 1; i < 10001; i++) {
regular(i, function(odd, even) {
if (odd) g = g + (odd * 2);
else g = g + (even * 3);
});
}
console.log('g:', g); // g: 125015000
t.stop();
var t2 = timer('promise');
var h = 0;
for (var i = 1; i < 10001; i++) {
promise(i).then(function(x) {h = h + (x*3);}).catch(function(x) {h = h + (x*2);});
}
console.log('h:', h); // h: 0
t2.stop();
What interesting is, the promises doesn't change the global variable 'h', how can I make it return the same result as variable 'g'?
UPDATE
Here is changed code that try to get the final result, but the non-deterministic of promises give us unexpected result.
for (var i = 1; i < 10001; i++) {
promise(i).then(function(x) {
h = h + (x*3); if (x===10000) console.log('h:', h);
}).catch(function(x) {h = h + (x*2);}); // h: 75015000
}
Currently my code that give the expected output is even stranger.
for (var i = 1; i < 10001; i++) {
promise(i).then(function(x) {
h = h + (x*3);
}).catch(function(x) {
h = h + (x*2);
if (x===9999) console.log('h:', h); // <- attention here
}); // h: 125015000
}
Can anyone show me a better code and explain the code above? (The code above shows the deterministic correct result when i is 9999 not 10000)
Promises ALWAYS call their .then() or .catch() handlers asynchronously. Even if they are resolved immediately, they will let the current thread of JS finish executing and will call the .then() or .catch() handlers asynchronously on the "next tick".
Thus your console.log('h:', h); is executed BEFORE any of then .then() handlers from the loop have been called. If you put the console.log() statement inside the .then() and .catch() handlers, you will find they are getting called, but AFTER your console.log('h:', h); is called.
Promises are designed to be an asynchronous interface. And, it's very important that an asynchronous interface is always consistent so even if the promise is resolved synchronously, they still call their .then() and .catch() handlers asynchronously on the next tick so that they are always consistent and the developer using them doesn't need to worry about sometimes getting an async response and sometimes getting a sync response. Instead, they are always async responses.
As I said in my comment, any real world coding situation should only use promises for operations that are at least sometimes asynchronous. If your operation is always synchronous (as your above example is), then they should not use promises because promises just make synchronous operations more complicated than just using straight synchronous function calls.
In addition, your multiple promise operations in your loop are not sequenced or coordinated in any given way. If these were real async operations, they could complete in any order and your updating of the h variable would have an uncertain order (which is often a problem and thus is usually a bad design pattern).
To solve your problem with promises you can wrap all the then methods with reduce and listen to all Promises finish, this is running the promises sequentially.
if you like you can use also Promise.all() to run in all the promises in parallel.
function promise (a) {
return new Promise (function (resolve, reject) {
if (a % 2 === 0) resolve(a);
else reject(a);
});
};
var timer = function(name) {
var start = new Date();
return {
stop: function() {
var end = new Date();
var time = end.getTime() - start.getTime();
console.log('Function:', name, 'finished in', time, 'ms');
}
};
};
console.log('Right result', Array.from({length : 10000}, (el, i)=> (i + 1) % 2 === 0 ? (i+1)*3 : (i+1)*2).reduce((a,b)=> a + b));
var t2 = timer('promise');
var h = 0;
Promise.all(Array.from({length : 10000}, (el, i)=> promise(i + 1).then(x =>{ h += x*3}).catch(x =>{ h += x*2 })
))
.then(()=>{
console.log('h:', h);
t2.stop();
});

Categories

Resources