I am learning javascript Promise. I have created 2 independent functions and am chaining them in a promise function. However the second function gets called first even though it is in the second then() block.
Code is below.
const one = document.getElementById('one');
function clkw(a){
setTimeout(() => {
one.innerHTML = a;
return 2*a;
}, 2000);
}
function clkw2(b){
setTimeout(() => {
one.innerHTML += ' '+b;
}, 2000);
}
function trypromise(){
const np = new Promise(resolve => {
setTimeout(() => {
resolve(10)
}, 2000);
});
np
.then(function(data){
return clkw(data);
})
.then(function(bata){
clkw2(bata);
});
}
If you want to chain and still be able to execute async code in the then continuation, you have to return a promise that resolves only when the result is ready.
In your snippet you don't actually return any values (or promises) from chained thens that can be used down the pipeline. Because of that, the result is automatically converted to a resolved promise that doesn't have any value.
const one = document.getElementById('one');
function clkw(a){
return new Promise(res => {
setTimeout(() => {
one.innerHTML = a;
res(2*a);
}, 2000);
});
}
function clkw2(b){
return new Promise(res => {
setTimeout(() => {
one.innerHTML += ' '+b;
res();
}, 2000);
});
}
function trypromise(){
const np = new Promise(resolve => {
setTimeout(() => {
resolve(10)
}, 2000);
});
np
.then(function(data){
return clkw(data);
})
.then(function(bata){
clkw2(bata);
});
}
trypromise();
<div id='one'></div>
However the second function gets called first even though it is in the second then() block.
Everything works as expected in the code you provided. How did you observe the strange behavior?
const one = document.getElementById('one');
function clkw(a) {
console.log("clkw");
setTimeout(() => {
one.innerHTML = a;
return 2 * a;
}, 2000);
}
function clkw2(b) {
console.log("clkw2");
setTimeout(() => {
one.innerHTML += ' ' + b;
}, 2000);
}
function trypromise() {
const np = new Promise(resolve => {
setTimeout(() => {
resolve(10)
}, 2000);
});
np
.then(function(data) {
return clkw(data);
})
.then(function(bata) {
clkw2(bata);
});
}
trypromise()
<div id="one"></div>
Related
Trying to learn proper async/await JavaScript to run functions in sequence when an early function in the sequence would be delayed (using setTimeout to simulate). I'm not getting the expected results (still getting "first", "second", "this should run first?" - see code).
What am I missing? Do I have the wrong idea about this?
Thanks in advance!
const zeroFunction = () => {
setTimeout(() => {
return new Promise((resolve) => {
console.log("This should run first?");
resolve();
});
}, 2000)}
const firstFunction = () => {
return new Promise((resolve) => {
console.log("first");
resolve();
})
}
const secondFunction = () => {
return new Promise((resolve) => {
console.log("second");
resolve();
})
}
async function fnAsync() {
await zeroFunction();
await firstFunction();
secondFunction();
}
fnAsync();
zeroFunction is currently returning undefined implicitly, not a Promise. Inverse the wrapping of the setTimeout and Promise constructor and it should work as expected.
const zeroFunction = () => {
return new Promise((resolve) => {
setTimeout(() => {
console.log("This should run first?")
resolve()
}, 2000)
})
}
const firstFunction = () => {
return new Promise((resolve) => {
console.log("first")
resolve()
})
}
const secondFunction = () => {
return new Promise((resolve) => {
console.log("second")
resolve()
})
}
async function fnAsync() {
await zeroFunction()
await firstFunction()
secondFunction()
}
fnAsync()
I have old-style library with 4 asynchronous functions - lets call them libA, libB, libC, libD (the running time of each is unknown/random) - when they finish they call my callback
I write loadString function which return observable (which should contains results of each callback function - I use string here for simplicity but it can be array of results) but it gives wrong result "AADDDDD". The expected result is "AADDDDDCCCCBBB". How to do it right using rxjs?
function loadString() {
let result = '';
return Observable.create(observer =>{
libA( n=> { result+='A'.repeat(n) });
libB( n=> { result+='B'.repeat(n) });
libC( n=> { result+='C'.repeat(n) });
libD( n=> {
result+='D'.repeat(n);
observer.next(result);
});
})
}
Below there is working snippet which you can copy to your answer and develop loadString function
// SET-UP
const { of, Observable } = rxjs;
const { map, switchMap, delay } = rxjs.operators;
// simulated lib function - not change this (the times are random)
function libA(callback) { setTimeout( _=>callback(2), 1000); }
function libB(callback) { setTimeout( _=>callback(3), 3000); }
function libC(callback) { setTimeout( _=>callback(4), 2000); }
function libD(callback) { setTimeout( _=>callback(5), 1500); }
// QUESTION: how to write below function body using rxjs?
function loadString() {
let result = '';
return Observable.create(observer =>{
libA( n=> { result+='A'.repeat(n) });
libB( n=> { result+='B'.repeat(n) });
libC( n=> { result+='C'.repeat(n) });
libD( n=> {
result+='D'.repeat(n);
observer.next(result);
});
})
}
// TEST
let s = loadString().subscribe(str=> {
console.log(str); // wrong result: I expected "AADDDDDCCCCBBB" value
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.5/rxjs.umd.min.js" integrity="sha256-85uCh8dPb35sH3WK435rtYUKALbcvEQFC65eg+raeuc=" crossorigin="anonymous"></script>
UPDAE
I would like to not run lib functions in sequential way but parallel (they send some requests to API...)
A hacked together solution that illustrates your problem - you should only call observer.next after your last callback has been called. Just keep a running count. The below code isn't important, the knowledge of, "just wait until your last one gets called before emitting" is the key.
Here's the hacked together solution for the fun of it:
// SET-UP
const { of, Observable } = rxjs;
const { map, switchMap, delay } = rxjs.operators;
// simulated lib function - not change this (the times are random)
function libA(callback) { setTimeout( _=>callback(2), 1000); }
function libB(callback) { setTimeout( _=>callback(3), 3000); }
function libC(callback) { setTimeout( _=>callback(4), 2000); }
function libD(callback) { setTimeout( _=>callback(5), 1500); }
// QUESTION: how to write below function body using rxjs?
function loadString() {
let result = '';
const done = (observer,count) => val => {
result += val;
// THIS IF STATEMENT IS WHAT YOU WERE MISSING
if(!--count) return observer.next(result);
}
return Observable.create(observer =>{
const complete = done(observer,4);
libA( n=> complete('A'.repeat(n))),
libB( n=> complete('B'.repeat(n))),
libC( n=> complete('C'.repeat(n))),
libD( n=> complete('D'.repeat(n)));
})
}
// TEST
let s = loadString().subscribe(str=> {
console.log(str); // wrong result: I expected "AADDDDDCCCCBBB" value
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.5/rxjs.umd.min.js" integrity="sha256-85uCh8dPb35sH3WK435rtYUKALbcvEQFC65eg+raeuc=" crossorigin="anonymous"></script>
Call each libX function from the callback of the previous one.
function loadString() {
let result = '';
return Observable.create(observer => {
libA(n => {
result += 'A'.repeat(n);
libB(n => {
result += 'B'.repeat(n);
libC(n => {
result += 'C'.repeat(n);
libD(n => {
result += 'D'.repeat(n);
observer.next(result);
});
});
});
})
});
}
libD is the ONLY thing that calls observer.next. As soon as that finishes, your observable will emit, even if the other ones haven't finished. So you need to wait. Try combineLatest (although that won't preserve order)?
// SET-UP
const { of, Observable, combineLatest } = rxjs;
const { map, switchMap, delay } = rxjs.operators;
// simulated lib function - not change this (the times are random)
function libA(callback) { setTimeout( _=>callback(2), 1000); }
function libB(callback) { setTimeout( _=>callback(3), 3000); }
function libC(callback) { setTimeout( _=>callback(4), 2000); }
function libD(callback) { setTimeout( _=>callback(5), 1500); }
// QUESTION: how to write below function body using rxjs?
function loadString() {
let result = '';
return combineLatest(
Observable.create(observer => libA(n => observer.next('A'.repeat(n)))),
Observable.create(observer => libB(n => observer.next('B'.repeat(n)))),
Observable.create(observer => libC(n => observer.next('C'.repeat(n)))),
Observable.create(observer => libD(n => observer.next('D'.repeat(n))))
);
}
// TEST
let s = loadString().subscribe(str=> {
console.log(str); // wrong result: I expected "AADDDDDCCCCBBB" value
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.5/rxjs.umd.min.js" integrity="sha256-85uCh8dPb35sH3WK435rtYUKALbcvEQFC65eg+raeuc=" crossorigin="anonymous"></script>
We can also use bufferCount (technique from here )
// SET-UP
const { Subject } = rxjs;
const { take, bufferCount, map, finalize } = rxjs.operators;
// simulated lib function - not change this (the times are random)
function libA(callback) { setTimeout( _=>callback(2), 1000); }
function libB(callback) { setTimeout( _=>callback(3), 3000); }
function libC(callback) { setTimeout( _=>callback(4), 2000); }
function libD(callback) { setTimeout( _=>callback(5), 1500); }
function loadString() {
let result = new Subject();
libA( n=> { result.next('A'.repeat(n)); });
libB( n=> { result.next('B'.repeat(n)); });
libC( n=> { result.next('C'.repeat(n)); });
libD( n=> { result.next('D'.repeat(n)); });
return result.pipe(
bufferCount(4), // num of callbacks
take(1), // this will unsubscribe after 4 values received
map( r => r.join`` ),
);
}
// TEST
let s = loadString().subscribe(str=> {
console.log(str); // wrong result: I expected "AADDDDDCCCCBBB" value
}, e=>{}, ()=> console.log('final'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.5/rxjs.umd.min.js" integrity="sha256-85uCh8dPb35sH3WK435rtYUKALbcvEQFC65eg+raeuc=" crossorigin="anonymous"></script>
or less efficient scan (because it concat strings not once but everytime some task ends)
// SET-UP
const { Subject } = rxjs;
const { scan, take, last, map } = rxjs.operators;
// simulated lib function - not change this (the times are random)
function libA(callback) { setTimeout( _=>callback(2), 1000); }
function libB(callback) { setTimeout( _=>callback(3), 3000); }
function libC(callback) { setTimeout( _=>callback(4), 2000); }
function libD(callback) { setTimeout( _=>callback(5), 1500); }
function loadString() {
let result = new Subject();
libA( n=> { result.next('A'.repeat(n)); });
libB( n=> { result.next('B'.repeat(n)); });
libC( n=> { result.next('C'.repeat(n)); });
libD( n=> { result.next('D'.repeat(n)); });
return result.pipe(
take(4),
scan((acc, value) => acc + value),
last()
);
}
// TEST
let s = loadString().subscribe(str=> {
console.log(str); // wrong result: I expected "AADDDDDCCCCBBB" value
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.5/rxjs.umd.min.js" integrity="sha256-85uCh8dPb35sH3WK435rtYUKALbcvEQFC65eg+raeuc=" crossorigin="anonymous"></script>
On the second then method there is a closed value(string), and I'm running setTimeout to change it after 1 second.
Also I'm returnin new Promise to resolved with setTimeout after 2 second to the value I'm changing with the previous setTimeout.
But after it resolved next then method logs out the value that is not affected by previous setTimeout.
Shouldn't I get 'foobarbaz' from the last then method's log.
Thanks in advance...
var p1 = new Promise((resolve, reject) => {
resolve('foo');
});
p1.then(function(string) {
return new Promise(res => {
setTimeout(() => {
string += 'bar';
res(string);
}, 2000);
});
})
.then(function(string) {
setTimeout(function() {
string += 'baz';
console.log(string);
}, 1000);
return new Promise(resolve => setTimeout(resolve, 2000, string));
})
.then(function(string) {
console.log(string);
});
The issue is:
return new Promise(resolve => setTimeout(resolve, 2000, string));
This results in setTimeout getting an argument of what is currently in the string variable at the moment that line is run - although string gets reassigned in the upper setTimeout, that setTimeout hasn't run yet, so string remains foobar.
Similarly:
let a = 'foo';
setTimeout(console.log, 200, a);
a = 'bar';
results in foo being logged, not bar.
If you pass a function that, when called, references what string is bound to when said function is called, results will be as expected:
return new Promise(resolve => setTimeout(() => {
resolve(string);
}, 2000));
var p1 = new Promise((resolve, reject) => {
resolve('foo');
});
p1.then(function(string) {
return new Promise(res => {
setTimeout(() => {
string += 'bar';
res(string);
}, 2000);
});
})
.then(function(string) {
setTimeout(function() {
string += 'baz';
console.log(string);
}, 1000);
return new Promise(resolve => setTimeout(() => {
resolve(string);
}, 2000));
})
.then(function(string) {
console.log(string);
});
I have three functions prints 20,30,10 as per setTimeout how should i make them print 10,20,30 order using promise
How to write these callbacks to print right order.
P.S. : This is not a duplicate question. Thanks !
var A = function(callback) {
setTimeout(function() {
console.log(10)
callback();
}, 2000);
};
var B = function(callback) {
console.log(20);
callback();
};
var C = function(callback) {
setTimeout(function() {
console.log(30)
callback();
}, 200);
};
function runTask() {
var wait = ms => new Promise ((resolve,reject) => setTimeout(resolve, ms))
var FuncA = wait();
FuncA.then(() => A(function () {}))
. then(() => B(function () {}))
.then(() => C(function () {}));
}
runTask();
I'm not 100% sure I understood your question. But, here it is based on what I understood. You weren't doing anything with the callback so I didn't pass them.
In your code function B didn't have a delay.
function delayAsync(ms) {
return new Promise(p_resolve => setTimeout(p_resolve, ms));
}
async function A(callback) {
await delayAsync(2000);
console.log(10);
if (callback instanceof Function) {
callback();
}
}
async function B(callback) {
console.log(20);
if (callback instanceof Function) {
callback();
}
}
async function C(callback) {
await delayAsync(200);
console.log(30);
if (callback instanceof Function) {
callback();
}
}
function runTask() {
return new Promise(async (resolve, reject) => {
await A();
await B();
await C();
resolve();
});
}
runTask().then(() => console.log('done'));
If you want to stick with Promises, you could create a helper function that performs a setTimeout but returns a Promise. This will preserve the order of console logs:
const setTimeoutAsync = (fn, ms) => new Promise(resolve => setTimeout(() => resolve(fn()), ms));
var A = function(callback) {
return setTimeoutAsync(() => {
console.log(10)
callback();
}, 2000);
};
var B = function(callback) {
console.log(20)
callback();
};
var C = function(callback) {
return setTimeoutAsync(() => {
console.log(30)
callback();
}, 200);
};
function runTask() { // refactored since A now returns a Promise
return A(() => {})
.then(() => B(() => {}))
.then(() => C(() => {}));
}
runTask();
Alternatively, if you'd like a clean solution and don't mind adding a third party module, you could use async-af, a library for chainable asynchronous JavaScript methods that I maintain:
const setTimeoutAsync = (fn, ms) => new Promise(resolve => setTimeout(() => resolve(fn()), ms));
var A = function(callback) {
return setTimeoutAsync(() => {
console.log(10)
callback();
}, 2000);
};
var B = function(callback) {
console.log(20)
callback();
};
var C = function(callback) {
return setTimeoutAsync(() => {
console.log(30)
callback();
}, 200);
};
// to run in parallel you would omit `series`, but
// since you want to run the tasks in order include it:
function runTask(...tasks) {
return AsyncAF(tasks).series.forEach(task => task(() => {}));
}
runTask(A, B, C);
<script src="https://unpkg.com/async-af#7.0.11/index.js"></script>
For example, look at this code:
function myPromise() {
return new Promise(resolve => {
setTimeout(() => {
resolve('Stack Overflow');
}, 2000);
});
}
async function sayHello() {
const externalFetchedText = await myPromise();
console.log('Hello ' + externalFetchedText);
}
sayHello();
What's the right way for showing a (.gif image file) loading before the request and hide this after Promise is resolved and the process is finished?
Most of time promises are abstracted into seprated module and are independent. So you should never do any other operation than async operation in the promises. You can show your gif while resolving the promises. See below code to show animation after you make async call, and hide it after resolution. You also have to handle reject scenario via try/catch/finally block.
function myPromise() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Stack Overflow');
// reject('Some Error')
}, 2000);
});
}
function showSpinner() {
document.getElementById('loader').style.display = 'block';
}
function hideSpinner() {
document.getElementById('loader').style.display = 'none';
}
async function sayHello() {
try {
showSpinner()
const externalFetchedText = await myPromise();
console.log('Hello ' + externalFetchedText);
} catch (err) {
console.error(err);
} finally {
hideSpinner()
}
}
sayHello();
<img id="loader" style="display:none" src="http://chimplyimage.appspot.com/images/samples/classic-spinner/animatedCircle.gif" />
You can do it in the promise if you want all the calling code that uses this promise to display the loading animation.
function myPromise() {
return new Promise(resolve => {
// Show image
setTimeout(() => {
// Hide image
resolve('Stack Overflow');
}, 2000);
});
}
async function sayHello() {
const externalFetchedText = await myPromise();
console.log('Hello ' + externalFetchedText);
}
sayHello();
function myPromise() {
return new Promise((resolve, reject) => {
setTimeout(() => {
//resolve('Stack Overflow');
reject('hello world');
}, 2000);
});
}
const newPromise = myPromise().then(result => {
"hide here"
return result;
}).catch(error => {
"hide here"
return error
});
async function sayHello() {
const externalFetchedText = await newPromise;
console.log('Hello ' + externalFetchedText);
}
sayHello();