What are the advantages using the chain with '.then' if it does not work like a expected:
new Promise(function(resolve, reject) {
// A mock async action using setTimeout
setTimeout(function() { resolve(10); }, 3000);
})
.then(function(num) {
console.log('first then: ', num); return num * 2; })
.then(function(num) {
setTimeout(function() {
console.log('second then: ', num); return num * 2; }, 500);
})
.then(function(num) {
console.log('last then: ', num);
});
// RESULT!
// From the console:
// first then: 10
// last then: undefined
// second then: 20
I was expecting for the following result:
// RESULT!
// From the console:
// first then: 10
// second then: 20
// last then: 40
The second then has to return another promise if you want the third then to fire after the timeout in the second then.
This version of your code will give you the desired result:
new Promise(function (resolve) {
setTimeout(function() {
resolve(10);
}, 3000);
})
.then(function (num) {
console.log('first then: ', num); return num * 2;
})
.then(function (num) {
return new Promise(function (resolve) {
setTimeout(function () {
console.log('second then: ', num);
resolve(num * 2);
}, 500);
});
})
.then(function (num) {
console.log('last then: ', num);
});
The reason why your code didn't work as expected was that the third then was invoked immediately after the second timeout started, with the result of the call to setTimeout, which is undefined.
I looks like you expected the result you are returning from the callback of the second timeout to be somehow passed as result of the second then, but that's not the way it works.
Related
a decorator function that slows down the execution of an arbitrary function by 5 seconds.
function someFunction(a, b) {
console.log(a + b);
}
function slower(func, seconds) {
// decorator code
}
let slowedSomeFunction = slower(someFunction, 5);
slowedSomeFunction()
// will output to the console "You will get you result in 5 seconds"
//...in 5 seconds will display the result of 'someFunction*'
attempts were unsuccessful, there are errors in the code
function someFunction(x) {
alert(x);
}
function slower(func, seconds) {
return function() {
setTimeout(() => func.apply(this, arguments), seconds);
}
}
let slowedSomeFunction = slower(alert, 5);
slowedSomeFunction('You will get you result in 5 seconds');
Try this :
function someFunction(a, b) {
console.log(a + b);
}
function slower(func, seconds) {
return function() {
console.log("You will get your result in " + seconds + " seconds");
setTimeout(() => func.apply(this, arguments), seconds * 1000);
}
}
let slowedSomeFunction = slower(someFunction, 5);
slowedSomeFunction(2, 3);
I'm not exactly sure to understand what you're trying to do but your function seems to work. The only issue is that the setTimeout() takes an argument in milliseconds and not seconds so you need to multiply it by 1 000 if you want seconds:
function someFunction(x) {
alert(x);
}
function slower(func, seconds) {
return function() {
setTimeout(() => func.apply(this, arguments), seconds*1000);
}
}
let slowedSomeFunction = slower(someFunction, 5);
slowedSomeFunction('Chill out, you will get you result in 5 seconds');
I have a class with multiple methods, each method either call async functions, or manipulating data created by other methods.
How can I make sure that calling class methods would wait for previous method finish before proceeding?
Here is a simple example that calls random methods of the class, each method takes random number of seconds to execute, I need to make sure that each called method waited for result of previous method:
class Test
{
constructor()
{
//ignore the constructor, it's simplified for this example and does not play any role in the question
const list = [...Array(~~(Math.random()*3)+3)].map(e=>~~(Math.random()*3+1));
console.log("expected: " + list);
list.forEach(f => this["method_" + f]());
}
method_1()
{
return new Promise(resolve => setTimeout(() =>
{
console.log(1);
resolve("res 1");
}, Math.random() * 1000 + 100));
}
method_2()
{
return new Promise(resolve => setTimeout(() =>
{
console.log(2);
resolve("res 2");
}, Math.random() * 1000 + 100));
}
method_3()
{
func3();
}
}
new Test();
function func3()
{
new Promise(resolve => setTimeout(() =>
{
console.log(3);
resolve("res 3");
}, Math.random() * 1000 + 100));
}
I can't use then method, because each method doesn't know which method was executed before it...or can I?
I was thinking about adding a sort of queue, where called method would be placed when called, and executed when previous promise was resolved...not sure if that would be a best approach.
Since essentially I needed make this class synchronous, using queue suggested by #Bergi works well:
class Test
{
constructor()
{
this.queueList = Promise.resolve();
//ignore the rest of the constructor, it's simplified for this example and does not play any role in the question
const list = [...Array(~~(Math.random()*3)+3)].map(e=>~~(Math.random()*3+1));
console.log("expected: " + list);
list.forEach(f => this["method_" + f]());
}
queue(func)
{
return (this.queueList = this.queueList.then(func).catch(console.error));
}
method_1()
{
return this.queue(() => new Promise(resolve => setTimeout(() =>
{
console.log(1);
resolve("res 1");
}, Math.random() * 1000 + 100)));
}
method_2()
{
return this.queue(() => new Promise(resolve => setTimeout(() =>
{
console.log(2);
resolve("res 2");
}, Math.random() * 1000 + 100)));
}
method_3()
{
return this.queue(func3);
}
}
new Test();
function func3()
{
return new Promise(resolve => setTimeout(() =>
{
console.log(3);
resolve("res 3");
}, Math.random() * 1000 + 100));
}
I wrote a function to get a random number after 500 milliseconds and it worked perfectly with (return new Promise (resolve,reject)), also, it worked without it by using setTimeout() function, but when I added the promise and setTimeout() inside it wont show the result, I have console.log() before and after the result and both are showing. Please note that i am still new to the promise concept in general since this is a task from my coding school, thank you.
My code:
function getRandomNumber () {
new Promise ((resolve,reject) =>{
console.log('Getting Random Number...');
let number = Math.random();
setTimeout( () => {
if(number){
resolve (`OK ${number}`);
console.log('Done!');
}
else
reject ('ERROR');
}, 500);
});
}
getRandomNumber();
Result:
First, return your promise, second use the result the promise provides either by creating a variable from it and awaiting it or using then
function getRandomNumber() {
return new Promise((resolve, reject) => {
console.log('Getting Random Number...');
let number = Math.random();
setTimeout(() => {
if (number) {
resolve(`OK ${number}`);
console.log('Done!');
} else {
reject('ERROR');
}
}, 500);
});
}
getRandomNumber().then(result => console.log(result));
(async () => {
const number = await getRandomNumber();
console.log(number);
})();
Another option is to write sleep as a separate reusable function. Note async function can await multiple values and return values of their own. Calling an async function will always return a Promise -
function sleep(time) {
return new Promise(resolve => setTimeout(resolve, time))
}
async function getRandomNumber() {
console.log('Getting Random Number...')
await sleep(500)
const number = Math.random()
console.log("Done!")
return number
}
async function main() {
const number1 = await getRandomNumber()
console.log("number1", number1)
const number2 = await getRandomNumber()
console.log("number1", number2)
const number3 = await getRandomNumber()
console.log("number1", number3)
return number1 + number2 + number3
}
main().then(console.log, console.error)
.as-console-wrapper { min-height: 100%; }
Getting Random Number...
Done!
number1 0.2907058138817884
Getting Random Number...
Done!
number1 0.05784624607512423
Getting Random Number...
Done!
number1 0.889702848981964
1.2382549089388766
You need to return the promise then you can use await inside async function to get the result
function getRandomNumber () {
return new Promise ((resolve,reject) =>{
console.log('Getting Random Number...');
let number = Math.random();
setTimeout( () => {
if(number){
resolve (`OK ${number}`);
console.log('Done!');
}
else
reject ('ERROR');
}, 500);
});
}
const printNumber = async () => console.log(await getRandomNumber());
printNumber();
CODE 1
console.log('start');
const interval = setInterval(() => {
console.log('setInterval');
}, 0);
setTimeout(() => {
console.log('setTimeout 1');
Promise.resolve()
.then(() => {
console.log('promise 3');
})
.then(() => {
console.log('promise 4');
})
.then(() => {
setTimeout(() => {
console.log('setTimeout 2');
Promise.resolve()
.then(() => {
console.log('promise 5');
})
.then(() => {
console.log('promise 6');
})
.then(() => {
clearInterval(interval);
});
}, 0);
});
}, 0);
Promise.resolve()
.then(() => {
console.log('promise 1');
})
.then(() => {
console.log('promise 2');
});
The result of this code on Windows Edge/Mac Safari/Opera browsers is as follow:
start
promise 1
promise 2
setInterval
setTimeout 1
promise 3
promise 4
setInterval
setTimeout 2
promise 5
promise 6
But when ran on chrome on Windows or Mac, the result have two cases.
Sometimes the result is same as above.
Sometimes the result outputs two setInterval as follow:
start
promise 1
promise 2
setInterval
setTimeout 1
promise 3
promise 4
setInterval
setInterval
setTimeout 2
promise 5
promise 6
I'm confused about the result.
CODE 2
function expendTime(k){
console.log((new Date()).getTime());
while(k < 10000){
for(var j = 2; j < k; j++){
if(k%j == 0){
break;
}
if(j == k-1){
console.log(k)
}
}
k++;
}
console.log((new Date()).getTime());
}
var t = setInterval(expendTime,15,3);
setTimeout(function() {
clearInterval(t);
},30);
.as-console-wrapper {
max-height: 100% !important;
}
The result of this code when ran on chrome and others browsers is different.
I consider the result on other browsers is correct, since it is coincides with my common sense.
Yes chrome's* implementation of setInterval does self-correct itself so its calls do fire at exact intervals, removing any drift.
*and maybe Edge's one ?
Here is an example code which does implement such a drift-correcting setInterval method, ran in chrome, you can see it has the same effect than the builtin one, while other implementations and recursive setTimeout will keep growing the drift.
// drift-correcting setInterval
// returns an object which "_id" property is the inner timeout id, so it can be canceled by clearInterval
function driftCorrectingInterval(cb, delay) {
var begin = performance.now(), // what time is it?
result = {
_id: setTimeout(inner, delay)
},
passed = true; // a flag to avoid try-catch the callback
return result;
function inner() {
if (!passed) return; // 'cb' thrown
passed = false; // set up the callback trap
var now = performance.now(),
drift = (now - begin) - delay;
begin += delay; // start a new interval
result._id = setTimeout(inner, delay - drift);
// call it at the end so we can cancel inside the callback
cb();
passed = true; // didn't throw we can continue
}
}
// snippet-only tests
function test(ms) {
function setTimeoutLoop(cb, ms) {
function loop() {
cb();
setTimeout(loop, ms);
}
setTimeout(loop, ms);
}
var now = performance.now(),
built_in_prev = now,
timeout_prev = now,
sCI_prev = now,
built_in_elem = document.querySelector('#test_' + ms + ' .delay.built_in'),
timeout_elem = document.querySelector('#test_' + ms + ' .delay.timeout'),
sCI_elem = document.querySelector('#test_' + ms + ' .delay.sCI');
setInterval(() => {
var now = performance.now(),
delay = (now - built_in_prev) - ms;
built_in_prev += ms;
built_in_elem.textContent = Math.round(delay);
}, ms);
setTimeoutLoop(() => {
var now = performance.now(),
delay = (now - timeout_prev) - ms;
timeout_prev += ms;
timeout_elem.textContent = Math.round(delay);
}, ms);
driftCorrectingInterval(() => {
var now = performance.now(),
delay = (now - sCI_prev) - ms;
sCI_prev += ms;
sCI_elem.textContent = Math.round(delay);
}, ms);
}
test(1000);
[id^='test'] {
border: 1px solid;
padding: 0 12px
}
<div id="test_1000">
<p>built in setInterval drift: <span class="delay built_in">0</span>ms</p>
<p>built in setTimeout loop drift: <span class="delay timeout">0</span>ms</p>
<p>driftCorrectingInterval drift: <span class="delay sCI">0</span>ms</p>
</div>
Note that current specs read as Firefox's implementation, and as what you understood, i.e a recursive setTimeout, without any consideration for drift.
Indeed the timer initialization steps requires that when the repeat flag is set to true, the same arguments should be passed to the next timer initialization steps method.
But an open issue discusses this very problem and might lead to a revision of the specs so that UAs are encouraged to apply such drift-correction when possible.
So my thinking was right, when recursing with promises, we end up calling all chained callbacks for however many times we recurse, for example
function p() {
return new Promise(function (r) {
process.nextTick(r);
})
}
function recurse(count) {
return p().then(function () {
if (count < 10) {
console.log('count => ', count);
return recurse(++count);
}
}).then(function(){
console.log('a');
return 5;
});
}
recurse(1).then(function () {
console.log('done');
});
If you run the above, we get:
count => 1
count => 2
count => 3
count => 4
count => 5
count => 6
count => 7
count => 8
count => 9
a
a
a
a
a
a
a
a
a
a
done
Is there a way to register this callback with console.log('a') just once instead of registering it 10 times?
I don't think I want/need this function to be called 10 times, and would like to find a way to have it called just once.
I am actually just as interested in a similar solution for Observables, specifically RxJS5 Observables.
I guess the only solution is to nest the remainder of your code inside the first promise callback like so:
function p() {
return new Promise(function (r) {
process.nextTick(r);
})
}
function recurse(count) {
return p().then(function () {
if (count < 10) {
return recurse(++count);
} else {
// all your remaining code would have to go here
console.log('a');
return 5; // or return someOtherPromise() or anything
}
});
}
recurse(1).then(function () {
console.log('done');
});
If the recursion is synchronous, you can simply recurse within the .then's function
new Promise(res => {
res(); // dummy initial promise
}).then(() => {
function recurse(x) { // recursion inside then
console.log('x', x);
if (x < 10) return recurse(++x);
return x;
}
return recurse(1); // begin recursion
}).then(y => { // this only fires once recursion above is resolved
console.log('y', y);
return 5;
}).then(z => console.log('z', z));
// x 1
// ... (synchronous)
// x 10
// y 10 (value passed from resolving inner promise)
// z 5 (value returned from previous then)
Or if our recursive function is asynchronous, we can have it return a promise too, so you end up with a recursion which looks like this
function doWork() {
function addOne(x) {
return new Promise((res, rej) => {
// async bit here
res(x + 1);
});
}
function recurse(x) {
if (x < 10) return addOne(x).then(recurse);
return x;
}
return recurse(1);
}
And in a promise chain, would look like this
new Promise(res => {
res(); // dummy initial promise
}).then(() => {
return doWork();
}).then(y => {
console.log(y);
});