Reduced promise returns early - javascript

function timeout(delay) {
return new Promise((resolve, reject) => {
setTimeout(resolve, delay);
});
}
function printDots(delays) {
return delays.map((delay) => {
return timeout(delay).then(() => process.stdout.write('.'))
}).reduce((acc, prom) => acc.then(prom));
}
printDots([513, 3402, 1337, 4122]).then(() => process.stdout.write('DONE!'));
This prints .DONE!... but I expected that it would print ....DONE!

.then expects a function as it's arguments (onFullfilled, onRejected), any value that is not a function is totally ignored
However, prom in the reduce callback is a promise, so only the first promise will be waited for
simple change, marked below should fix things
function timeout(delay) {
return new Promise((resolve, reject) => {
setTimeout(resolve, delay);
});
}
function printDots(delays) {
return delays.map((delay) => {
return timeout(delay).then(() => process.stdout.write('.'))
}).reduce((acc, prom) => acc.then(() => prom));
// ^^^^^^
}
printDots([513, 3402, 1337, 4122]).then(() => process.stdout.write('DONE!'));
Note, however, that the promises will all be commenced at about the same time, no waiting for 0 to end before 1 starts etc
given this, an arguably better solution for printDots is to use Promise.all
function printDots(delays) {
return Promise.all(delays.map((delay) => timeout(delay).then(() => process.stdout.write('.'))));
}
As per comments, the promises need to run sequentially - that's as simple as only using reduce
function timeout(delay) {
return new Promise((resolve, reject) => {
setTimeout(resolve, delay);
});
}
function printDots(delays) {
return delays.reduce((acc, delay) => acc.then(() => timeout(delay).then(() => process.stdout.write('.'))), Promise.resolve());
}
printDots([513, 3402, 1337, 4122]).then(() => process.stdout.write('DONE!'));
In this case, you need to provide an initial promise (Promise.resolve) to reduce so that the first iteration is working with a promise like all subsequent ones are

Related

How to sleep a method in javascript method chaining

I am trying to make a method sleep(delay) in method chaining. For this I am using setTimeout with Promise. This will require any method following the sleep to be inside the then.
Right now I am calling the function like
lazyMan("John", console.log).eat("banana").sleep(5).then(d => {d.eat("apple");});.
Here is my code
function lazyMan(name, logFn) {
logFn(name);
return {
eat: function(val) {
console.log(val);
return this;
},
sleep: function(timer) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(`Sleeping for ${timer} seconds`);
resolve(this);
}, timer * 1000);
}).then(d => this);
}
};
}
lazyMan("John", console.log)
.eat("banana")
.sleep(5)
.then(d => {
d.eat("apple");
});
Is there a way I can modify my function to call it like lazyMan("John", console.log).eat("banana").sleep(5).eat("apple") and get the output in same order
I have gone through Add a sleep method in a object method chain(JS)
You can keep a promise for your "task queue", so anything that needs to be done, will be added onto there via .then(). This provides a fluent API for scheduling stuff.
function lazyMan(name, logFn) {
logFn(name);
let taskQueue = Promise.resolve();
const addTask = f => {
taskQueue = taskQueue.then(f);
}
return {
eat: function(val) {
addTask(() => console.log(`Eating [${val}]`));
return this;
},
sleep: function(timer) {
addTask(() => new Promise((resolve, reject) => {
console.log(`Start sleeping for ${timer} seconds`);
setTimeout(() => {
console.log(`End sleeping for ${timer} seconds`);
resolve();
}, timer * 1000);
}))
return this;
}
};
}
lazyMan("John", console.log)
.eat("banana")
.sleep(5)
.eat("apple");
Note that this change means that every action is technically asynchronous. However, that's at least uniform, so it's less of a chance of a surprise when keeping it in mind.

returning a promise from the then of another promise

i am a little new at this. Please help
I am trying to return a promise from a function. This seems to work well until I try to return the promise in the then of an existing promise.
I am trying to do this in a FireFox extension. The code below is written for node.js as I thought it might give more explanation. I cannot figure out how to make it work.
function topLevel calls function level2. level2 waits for a promise to resolve and then returns a promise to level1. level1 logs in its .then.
level2 calls level3 after its internal promise is resolved and returns a new promise
In the example all promises resolve immediately. The example is paired down to the essentials
function topLevel() {
level2()
.then(() => {
console.log("topLevel resolved")
})
}
let testError=true;
function level2() {
if(testError) {
new Promise((resolve, reject) => {
resolve("Level 2");
})
.then(() => {
return (level3());
})
}
else {
return (level3());
}
}
function level3(){
return (new Promise((resolve, reject) => {
resolve("Level 3");
}));
}
topLevel();
there is a variable "testError" which changes the behavior of level 2. When set to "true" level2 waits for a promise and returns a promise from level3 in that promises then statement. level3 is run but the console.log in level1 never executes and an error results. When set to false everything works (promise from level3 is returned directly rather than in .then. The error is Cannot read property 'then' of undefined in toplevel .then.
The firefox webextension code from a background script is below
browser.browserAction.onClicked.addListener(topLevel);
function topLevel() {
level2()
.then(() => {
console.log("topLevel resolved")
})
}
function level2() {
new Promise((resolve, reject) => {
resolve("Level 2");
})
.then(() => {
return (level3());
})
}
function level3(){
return (new Promise((resolve, reject) => {
resolve("Level 3");
}));
}
It causes a warning in level2 between the .then and return statements that
"level2 is undefined". and again the log in level one never happens.
Any way to make this work?? I need to rely on this pattern
level2 does not return anything when testError is true.
The thenable (the function given to then) is a function. The return statement inside the thenable only concern the thenable itself (just like any function).
Change to
function level2() {
if (testError) {
return new Promise((resolve, reject) => {
resolve("Level 2");
}).then(() => {
return level3();
});
}
return level3();
}
I think it's as simple as adding a return before new Promise... in line 12. Revised code:
function topLevel() {
level2()
.then(() => {
console.log("topLevel resolved")
})
}
let testError = true;
function level2() {
if(testError) {
// Added "return" here
return new Promise((resolve, reject) => {
resolve("Level 2");
})
.then(() => {
return (level3());
})
}
else {
return (level3());
}
}
function level3() {
return (new Promise((resolve, reject) => {
resolve("Level 3");
}));
}
You need to return the new Promise you create in the level2 function.

completion of one promise, before starting the next, in a long list

I discovered javascript promises recently. An advertised benefit is clean nesting by chaining then clauses.
My code works as expected, but nesting grows just as ugly as when I used callbacks. Is there a better way to use chaining of then to remove all this nesting? Note I need task n to complete before anything in task n+1 can start.
The very simple fixed example
'use strict';
function P1() {
return new Promise((resolve) => {
console.log("starting 1")
setTimeout(() => {
console.log("done 1")
resolve();
}, 100)
})
}
function P2() {
return new Promise((resolve) => {
console.log("must start 2 only after 1 is done")
setTimeout(() => {
console.log("done 2")
resolve();
}, 50)
})
}
function P3() {
return new Promise((resolve) => {
console.log("must start 3 only after 3 is done")
setTimeout(() => {
console.log("done 3")
resolve();
}, 10)
})
}
console.log("this works, but if list was long, nesting would be terribly deep");
// start 1, done 1, start 2, done 2, start 3, done 3.
P1().then(() => {
P2().then(() => {
P3()
})
})
Based on the feedback I should have done
P1().then(() => {
return P2()
}).then(() => {
return P3()
}).catch(() => { console.log("yikes something failed" )})
The real code receives an array of stuff to process sequentially.
The suggested format above appears suitable only when the sequence of steps is specified as code. Seems like there should some kind of Promise.do_these_sequentialy, rather than my code constructing the promise chain explicitly. As follows:
'use strict';
function driver(single_command) {
console.log("executing " + single_command);
// various amounts of time to complete command
return new Promise((resolve) => {
setTimeout(() => {
console.log("completed " + single_command);
resolve()
}, Math.random()*1000)
})
}
function execute_series_of_commands_sequentialy(commands) {
var P = driver(commands.shift());
if (commands.length > 0) {
return P.then(() => { return execute_series_of_commands_sequentialy(commands) })
} else {
return P
}
}
execute_series_of_commands_sequentialy([1, 2, 3, 4, 5, 6, 7, 8, 9]).then(() => {
console.log("test all done")
})
P1()
.then(() => P2())
.then(() => P3())
You can make your code more flat.
Also explicit construction is an antipattern
You misunderstood how Promises work. You can chain return values as well as Promise instances and pass them further along the chain:
P1()
.then(() => P2())
.then(() => P3())
There's no need to nest them.
Personally I like how this format looks and is what I use
foo(){
P1().then(()=>{
return P2();
}).then(()=>{
return P3();
}).catch((err)=>{
//handle errors
});
}
Have a look at async/await that greatly simplifies the writing of promises.
JavaScript’s Async/Await Blows Promises Away
Basically, it consists in writing async functions like sync code:
async function P(number) {
return new Promise((resolve) => {
console.log("starting "+number)
setTimeout(() => {
console.log("done "+number)
resolve();
}, 800)
})
}
/* Or the ES6 version :
const P = async (number) => new Promise((resolve) => { ... })
*/
async function run(){
await P(1)
await P(2)
await P(3)
console.log("All done!")
}
run()

How to chain a Promise.all with other Promises?

I want to execute my code in the following order:
Promise 1
Wait for 1 to be done, then do Promise 2+3 at the same time
Final function waits for Promise 2+3 to be done
I'm having some trouble figuring it out, my code so far is below.
function getPromise1() {
return new Promise((resolve, reject) => {
// do something async
resolve('myResult');
});
}
function getPromise2() {
return new Promise((resolve, reject) => {
// do something async
resolve('myResult');
});
}
function getPromise3() {
return new Promise((resolve, reject) => {
// do something async
resolve('myResult');
});
}
getPromise1()
.then(
Promise.all([getPromise2(), getPromise3()])
.then() // ???
)
.then(() => console.log('Finished!'));
Just return Promise.all(...
getPromise1().then(() => {
return Promise.all([getPromise2(), getPromise3()]);
}).then((args) => console.log(args)); // result from 2 and 3
I know it's an old thread, but isn't
() => {return Promise.all([getPromise2(), getPromise3()]);}
a little superfluous? The idea of fat arrow is that you can write it as:
() => Promise.all([getPromise2(), getPromise3()])
which makes the resulting code somewhat clearer:
getPromise1().then(() => Promise.all([getPromise2(), getPromise3()]))
.then((args) => console.log(args)); // result from 2 and 3
Anyway, thanks for the answer, I was stuck with this :)

Plain es6 promise; how to do n arbitrary operations?

I have two simple methods
// send a single command
sendCommand(command) {
return new Promise((resolve, reject) => {
this._commands.write(command, (response) => {
response === '?' : reject(command) : resolve(command);
});
});
}
// has to send multiple commands and wait for the result
sendArray(name, array) {
let bits = _.chunk(array, 4);
_.each(bits, (bit, index) => {
this.sendCommand(`QD ${name}[]${bits.join('\r')}\\`);
});
}
However, is there any way for this array be sent through the promises iteratively with plain es6 promises? Eg:
// for every bit in bits
this.sendCommand(bit1)
.then(() => { this.sendCommand(bit2) })
// ...
.then(() => { this.sendCommand(bitN) })
.catch(console.log);
Something like
let allBitsPromise = _.chunk(array, 4).reduce(function (p, bit) {
return p.then(() => sendCommand(bit));
}, Promise.resolve());
would work.
The least obvious part of this (to me, anyway) is that if the callback passed to then returns a promise p then the original promise is resolved when p is. So a promise like
Promise.resolve().then(() => {
return new Promise((resolve, reject) => setTimeout(resolve, 2000))
});
Is only resolved when the promise returned by the callback is resolved by setTimeout.
Keep a reference to the promise returned by the function and chain the .then call on it:
let promise = Promise.resolve();
_.each(bits, (bit, index) => {
promise = promise.then(() => this.sendCommand(`QD ${name}[]${bits.join('\r')}\\`));
});
promise.catch(error => console.log(error));
Note that this will send the data sequentially, which I assume is what you want.

Categories

Resources