How to use promise in while(JavaScript/Node.js)? - javascript

I'm trying to execute repeatly multiple processes in sequence by using promise and while (JavaScript/Node.js).
However, the promise function is not executed (i.e., all console.log() is never displayed).
Why is the promise function never executed in the while?
Also, how can I display the some console.log() repeatedly in sequence?
var count = 0;
while(count < 5) {
Promise.resolve()
.then(function () {
return new Promise(function(resolve, reject) {
console.log('func1()...');
resolve('OK');
});
})
.then(function(value) {
return new Promise(function(resolve, reject) {
console.log('func2()...');
resolve('OK');
});
})
.then(function (value) {
console.log('func3()...');
count++;
}).catch(function (error) {
console.log(error);
});
}

.then() still remains an asynchronous callback, see the order of messages here:
Promise.resolve().then(()=>console.log("got resolved"));
console.log("got here");
One thing you can do is wrap the code into an async function:
async function test(){
var count = 0;
while(count < 5) {
await Promise.resolve()
.then(function () {
return new Promise(function(resolve, reject) {
console.log('func1()...');
resolve('OK');
});
})
.then(function(value) {
return new Promise(function(resolve, reject) {
console.log('func2()...');
resolve('OK');
});
})
.then(function (value) {
console.log('func3()...');
count++;
}).catch(function (error) {
console.log(error);
});
}
}
test();

What is happening - in Javascript the event loop and source code you write is executed in one thread. It means that if this one thread is blocked by some work, nothing else is executed.
It works quite straightforward - event loop takes one event (code you show) and it processes ALL synchronous part and it pushes any asynchronous things (the promise chain) to event loop to be executed later.
The issue is this:
var count = 0;
while(count < 5) {
Promise.resolve()
.then(
// some promise chain...
}
The while is catched in never ending loop, as all the synchronous part is that it push this Promise chain in event loop and then starting again. The count is never changed in this context.
The best for you is to use async/await which solves exactly what you want without need deeply understand Node.js
The other option is to use recursion
function promiseChain() {
return Promise.resolve()
.then(function () {
return new Promise(function(resolve, reject) {
console.log('func1()...');
resolve('OK');
});
})
.then(function(value) {
return new Promise(function(resolve, reject) {
console.log('func2()...');
resolve('OK');
});
})
.then(function (value) {
console.log('func3()...');
count++;
}).catch(function (error) {
console.log(error);
});
}
recursivelyExecute(promise, count) {
if (count > 5) {
return;
}
count++;
return promise.then(() => recursivelyExecute(promiseChain(), count+1));
}

var count = 0;
while(count < 5) {
Promise.resolve()
.then(function () {
return new Promise(function(resolve, reject) {
console.log('func1()...');
resolve('OK');
});
})
.then(function(value) {
return new Promise(function(resolve, reject) {
console.log('func2()...');
resolve('OK');
});
})
.then(function (value) {
console.log('func3()...');
}).catch(function (error) {
console.log(error);
});
count++;
}

You need to use Promise.all() along with async.eachSeries for looping. For this you need to install async then do the following:
const async = require('async');
var count = [...Array(5).keys()];
async.eachSeries(count, (c, next) => {
Promise.all([
new Promise(function (resolve, reject) {
console.log('func1()...');
resolve('OK');
}),
new Promise(function (resolve, reject) {
console.log('func2()...');
resolve('OK');
})]).then(function (values) {
console.log('func3()...');
next();
});
}, (err) => {
console.log("here we done");
});

Related

Reject all functions if one is rejected

I have a similar problem in dialogflow fulfillment where I need to book any appointments on the Google calendar. I would reject all functions p1, p2 and p3 if only one of them is rejected. In the code below, although p2 is rejected, the others p1 and p3 are executed (I wish all functions p1, p2 and p3 were not performed).
function f1() {
return Promise.all([p1(), p2(), p3()])
.then(value => {
alert('ok');
})
.catch(err => {
console.log('err: ' + err);
});
}
function p1() {
new Promise((resolve, reject) => {
setTimeout(resolve, 1000, alert("one"));
});
}
function p2() {
new Promise((resolve, reject) => {
reject('reject');
});
}
function p3() {
new Promise((resolve, reject) => {
setTimeout(resolve, 3000, alert("three"));
});
}
f1();
Well it contains a lot of code to implement it so I would give short instructions.
You need to have a way to reject your request or whatever you are doing. For examples with axious we can use CancelToken to cancel HTTP request.
Now you need to subscribe on each request and cancel the request or whatever you are using.
It is not clear what exactly you need. Functions can not be rejected or not executed if you run them in parallel. You can only notify the internal function code that the cancel operation was requested from the outside. We don't know what async operations are performed inside your async functions. Demo
import { CPromise } from "c-promise2";
function makePromise(ms, label) {
return new CPromise((resolve, reject, { onCancel }) => {
setTimeout(resolve, ms);
onCancel(() => console.log(`onCancel(${label})`));
});
}
CPromise.all([
makePromise(2000, "one"),
makePromise(1500, "two").then(() => {
throw Error("Oops");
}),
makePromise(4000, "three")
]).then(
(v) => console.log(`Done: ${v}`),
(e) => console.warn(`Fail: ${e}`)
);
onCancel(one)
onCancel(three)
Fail: Error: Oops
The problem is you're not returning anything from p1, p2, p3. So when you call Promise.all([p1(), p2(), p3()]) which is actually calling with Promise.all([undefined, undefined, undefined])(resolves anyway) which does not have a rejection. That's why you're not seeing the error.
Add return in your functions.
function f1() {
return Promise.all([p1(), p2(), p3()])
.then(value => {
alert('ok');
})
.catch(err => {
console.log('err: ' + err);
});
}
function p1() {
return new Promise((resolve, reject) => {
setTimeout(resolve, 1000);
});
}
function p2() {
return new Promise((resolve, reject) => {
reject('reject');
});
}
function p3() {
return new Promise((resolve, reject) => {
setTimeout(resolve, 3000);
});
}
f1();
Remember Promises are not cancellable, if you really want cancel execution part, you can try something like this. I don't guarantee this works all the time and I don't think good idea to do in this way.
const timers = []
function f1() {
return Promise.all([p1(), p2(), p3()])
.then(value => {
alert('ok');
})
.catch(err => {
console.log('err: ' + err);
timers.forEach((timerId) => clearTimeout(timerId))
});
}
function p1() {
return new Promise((resolve, reject) => {
const timerId = setTimeout(() => {
alert(1)
resolve()
}, 1000);
timers.push(timerId)
});
}
function p2() {
return new Promise((resolve, reject) => {
reject('reject');
});
}
function p3() {
return new Promise((resolve, reject) => {
const timerId = setTimeout(() => {
alert(2)
resolve()
}, 3000);
timers.push(timerId)
});
}
f1();

Then function isn't called after returning a promise

I created a function to check if an element already exist, if not repeat the function until it does:
function waitForElementToDisplay(selector) {
return new Promise(function (resolve, reject) {
if (document.querySelector(selector) != null) {
console.log('Element is displayed now');
resolve();
} else {
setTimeout(function () {
waitForElementToDisplay(selector, 500);
}, 500);
}
})
}
I use this function in the beforeShowPromise function of Shepherd.js. This function let the package wait with going to the next tour step until the promise is resolved. The beforeShowPromise function looks like this:
beforeShowPromise: function () {
return new Promise(async function (resolve) {
const selector = '.exampleTemplates';
await waitForElementToDisplay(selector).then(() => {
console.log('Do something');
}).catch(err => {
console.log(err);
});
})
},
I want to wait until the waitForElementToDisplay function is resolved, so the function of Shepherd can be resolved. However, the .then nor the .catch functions are being called. Can someone explain to me why it isn't working?
The Promise only resolves if the element exists.
If it doesn't, you hit the else branch which calls the function recursively. This creates a new promise, but you never do anything when that resolves. The original promise is left sitting in limbo.
You can resolve the original promise with the new promise:
resolve( waitForElementToDisplay(selector) );
You need to pass along the resolve to the recursive call:
const checkIfElementExists = (resolve, selector) => {
if (document.querySelector(selector) !== null) {
console.log('Element is displayed now');
resolve();
} else {
setTimeout(checkIfElementExists, 500, resolve, selector);
}
};
function waitForElementToDisplay(selector) {
return new Promise(function(resolve) {
checkIfElementExists(resolve, selector);
})
}
Or, encapsulated inside waitForElementToDisplay:
function waitForElementToDisplay(selector) {
return new Promise(function(resolve) {
(function checkIfElementExists() {
if (document.querySelector(selector) !== null) {
console.log('Element is displayed now');
resolve();
} else {
setTimeout(checkIfElementExists, 500);
}
})();
})
}

How to execute functions sequentially using Node Js Promise?

I'm new to Node js Promise I'm not sure whether I'm using the Promise correctly or not so here is my code.
function print(){
first('first')
.then(second('second'))
.then(third('third'));
}
function first(a){
return new Promise((resolve, reject) => {
var res1 = function (){
resolve(a);
}
});
console.log(a);
}
function second(b){
return new Promise((resolve, reject) => {
var res1 = function (){
resolve(b);
}
});
setTimeout(() => {
console.log(b);
}, 2000);
}
function third(c){
return new Promise((resolve, reject) => {
var res1 = function (){
resolve(c);
}
});
console.log(c);
}
My desired output is
first
second
third
Instead what I get is
first
third
//after two seconds
second
I'm missing something but I can't figure it out please explain me
To get the expected behaviour, you need to resolve inside of the timeout (next to the console log). You also cannot pass arguments into promise chain functions since they need to accept the promise from the previous thennable.
A working snippet is below:
print();
function print(){
first('first')
.then(second)
.then(third);
}
function first(a){
return new Promise((resolve, reject) => {
console.log(a);
resolve(a);
});
}
function second(b){
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("second");
resolve(b);
}, 2000);
});
}
function third(c){
return new Promise((resolve, reject) => {
console.log("third");
resolve(c)
});
}

resolving a javascript promise

Below outlines a promise that has two simple steps display on the console something, then display something else after the first step is completed.
I am trying to understand how to resolve the promise, and allow the 2nd step to complete.
var lookup_documents = new Promise(
function(resolve, reject) {
console.log("1st");
//resolve(); - How do I do this outside of this function?
}
);
lookup_documents.then(
function() {
console.log("2nd");
}
);
Normally you use new Promise() when you want to wrap some asynchronous function into a promise, such as:
new Promise((resolve, reject) => {
makeAjaxCall((err, data) => {
if(err) return reject(err);
else return resolve(data);
})
});
There are other Promise implementations, such as q, where you can create a "deferred" object that returns a promise... Something similar would be:
function makeAjaxCallPromise() {
let deferred = Q.defer();
makeAjaxCall((err, data) => {
if(err) return deferred.reject(err);
else return deferred.resolve(data);
});
return deferred.promise;
}
For the specific thing you want... All I can think of is declare a variable outside of the promise function scope and asign it, something like:
let resolver, rejecter;
new Promise((resolve, reject) => {
resolver = resolve;
rejecter = reject;
});
makeAjaxCall((err, data) => {
if(err) return resolver(err);
else return rejecter(data);
});
But that doesn't look too good and can lead to errors... Try to wrap everything in your Promise function.
You can do it like this, using your example - if I understand you correctly.
var lookup_documents = function() {
return new Promise(function(resolve, reject) {
console.log("1st");
resolve();
});
};
lookup_documents().then(function() {
console.log("2nd");
});

How to return promise.map (bluebird) inside a promise chain?

I'm using a chain to control flow and can't get promise.map in step2() to wait until all of it's generated promises are resolved.
Here's a visual of the flow I'm trying to achieve.
step1()
step2()
step2()
step2()
step2()
step3()
In step2() I'm using Bluebird's promise.map.
Here's the chain:
step1()
.then(function() { return step2() })
.then(function() { return step3() })
.catch(function() { // handle errors })
Here's my functions for each step:
let step1 = function() {
return new Promise(function(resolve, reject) {
// do stuff
resolve()
})
}
let step2 = function() {
return new Promise(function(resolve, reject) {
things = []
return Promise.map(things, function(thing) {
// load file async with callback
})
resolve()
})
}
let step3 = function() {
return new Promise(function(resolve, reject) {
// do stuff
resolve()
})
}
I've tested the chain with many more steps each with a timeout and it worked as expected with the exception of the promise.map in step2(). What am I doing wrong? :)
The problem is from step 2. Promise.map already return promise, so you can just return it to callee. Then you warp the async function with callback with new Promise.
let step2 = function() {
things = []
return Promise.map(things, function(thing) {
// load file async with callback
return new Promise(function(resolve, reject) {
fileAsyncFunc(thing, function callback(err, data) {
if(err) {
reject(err);
return;
}
resolve(data);
});
});
});
}
You are not calling your resolve callback properly.
let step2 = function() {
things = []
return Promise.map(things, function(thing) {
return new Promise( function( resolve, reject ) {
// load file async with callback
resolve(...)
} )
})
}
In your case resolve() is always called, since you are executing async function for loading the file.

Categories