I would like to resolve my promise after my setTimeout will be finished. I have a few functions like step The main idea is to get step results sequentially. P.S. we can't mutate setTimeout.
function step (done) {
return new Promise((resolve, reject) => {
try {
setTimeout(done, 5100, 'hello world')
resolve()
} catch (error) {
reject()
}
})
}
If you can't mutate the setTimeout remove it. Instead of putting the setTimeout in the step function create a new delay function that returns a promise. You can then use async/await to walk through the steps after certain delays.
function delay(time = 1000) {
return new Promise(res => {
setTimeout(() => res(), time);
});
}
function step(fn, n) {
fn(`hello world ${n}`);
}
const fn = (str) => console.log(str);
async function main() {
step(fn, 1);
await delay(5000);
step(fn, 2);
await delay(3000);
step(fn, 3);
}
main();
If you can change the done function, you can do like below.
function step(done) {
return new Promise((resolve, reject) => {
immutableFunc(done(resolve, reject));
});
}
function immutableFunc(done) {
setTimeout(done, 1000, "hello world");
}
function done(resolve, reject) {
return arg => {
try {
console.log(arg);
resolve();
} catch (error) {
reject(error);
}
};
}
async function test() {
try {
await step(done);
await step(done);
await step(done);
} catch (err) {
console.log(err);
}
}
test();
Related
i have a promise chain
If i receive error in getServiceCost I want to repeat the chain again (retry) for 2 times how can i achieve this when using Promise chain , meaning again execute getUser, getServiceCost
getUser(100)
.then(getServices)
.then(getServiceCost)
.then(console.log);
function getUser(userId) {
return new Promise((resolve, reject) => {
console.log('Get the user from the database.');
setTimeout(() => {
resolve({
userId: userId,
username: 'admin'
});
}, 1000);
})
}
function getServices(user) {
return new Promise((resolve, reject) => {
console.log(`Get the services of ${user.username} from the API.`);
setTimeout(() => {
resolve(['Email', 'VPN', 'CDN']);
}, 3 * 1000);
});
}
function getServiceCost(services) {
return new Promise((resolve, reject) => {
console.log(`Calculate the service cost of ${services}.`);
setTimeout(() => {
resolve(services.length * 100);
}, 2 * 1000);
});
}
If i receive error in getServiceCost I want to repeat the chain again (retry) for 2 times how can i achieve this when using Promise chain , meaning again execute
getUser, getServiceCost
I'd use an async function (all modern environments support them, and you can transpile for obsolete environments), which lets you use a simple loop. Perhaps as a utility function you can reuse:
async function callWithRetry(fn, retries = 3) {
while (retries-- > 0) {
try {
return await fn();
} catch (error) {
if (retries === 0) {
throw error;
}
}
}
return new Error(`Out of retries`); // Probably using an `Error` subclass
}
Using it:
callWithRetry(() => getUser(100).then(getServices).then(getServiceCost))
.then(console.log)
.catch(error => { /*...handle/report error...*/ });
Or
callWithRetry(async () => {
const user = await getUser(100);
const services = await getServices(user);
return await getServiceCost(services);
})
.then(console.log)
.catch(error => { /*...handle/report error...*/ });
I have the following function that works fine, except I need to wait until it finishes to execute the next statement:
zohoAuth.zoho_oAuth = function () {
// return new Promise((resolve, reject) => {
zohoAuth.state = utils.uuid();
const url = zohoAuth.authorizationURL();
zohoAuth.popUp(url);
getAuthCodeFromCatalyst();
//setTimeout(getAuthCodeFromCatalyst,1000);
function getAuthCodeFromCatalyst() {
return new Promise(function (resolve, reject) {
(async function waitForFoo() {
const gotAuthState = await zohoAuth.getUserDataFromStorageState(zohoAuth.state)
await gotAuthState;
if (gotAuthState) return resolve();
setTimeout(waitForFoo, 1000);
})();
});
}
console.log("bottom of zoho auth")
return true;
// });
}
I call the function with this:
zohoAuth.zoho_oAuth();
console.log("done waiting");
How do i wait for this to finish?
You're making this harder on yourself. Make sure to avoid the explicit promise constructor anti-pattern -
zohoAuth.zoho_oAuth = function () {
zohoAuth.state = utils.uuid();
const url = zohoAuth.authorizationURL();
zohoAuth.popUp(url);
return zohoAuth.getUserDataFromStorageState(zohoAuth.state);
}
You can access the result by attaching a .then handler to the result of your function call -
zohoAuth.zoho_oAuth()
.then(authState => console.log("bottom of auth state", authState))
.catch(console.error)
If you want to use async and await, go ahead. If an error occurs, don't catch it. Instead allow it to bubble up and be handled by the caller -
async function doAuth (...) {
const authState = await zohoAuth.zoho_oAuth()
console.log("received auth state", authState)
return "done" // or whatever
})
doAuth().then(console.log, console.error)
You should consider awaiting on the promise. Below snippet shows the difference of using await -
const asyncFunction = function() {
return new Promise(function(resolve, reject) {
setTimeout(() => {
console.log('inside promise');
resolve();
}, 100);
});
}
function callWithoutAwait() {
asyncFunction();
console.log('after without await function');
}
callWithoutAwait();
async function callWithAwait() {
await asyncFunction();
console.log('after with await function');
}
callWithAwait();
I was able to accomplish what I needed below is the code. Thanks for the help!
zohoAuth.zoho_oAuth = function() {
zohoAuth.state = utils.uuid();
const url = zohoAuth.authorizationURL();
zohoAuth.popUp(url);
return new Promise(function (resolve, reject) {
(async function waitForFoo() {
const gotAuthState = await zohoAuth.getUserDataFromStorageState(zohoAuth.state)
await gotAuthState;
if (gotAuthState) return resolve();
setTimeout(waitForFoo, 1000);
})();
});
}
And this is the call:
zohoAuth.zoho_oAuth()
.then(authState => console.log("bottom of auth state", authState))
.catch(console.error)
In this simplified example, I am calling three functions when the first promise gets resolved.
var test = new Promise(function (res, err) { setTimeout(res, 3000) })
test.then( () => { console.log("A") });
test.then( () => {
return new Promise(function(res, err) {
setTimeout(()=> { console.log("C");
res() }, 3000)
});
});
test.then( () => { console.log("B") });
The output as expected is A B C.
Let's suppose that I want to invoke the third .then to console B only when the second promise gets resolved.
If I try to store the second promise (myProm) in global and attach a .then function on it, I'll get (reasonably) a TypeError because at compile time myProm is still undefined.
var test = new Promise(function (res, err) { setTimeout(res, 3000) })
var myProm;
test.then( () => { console.log("A") });
test.then( () => {
myProm = new Promise(function(res, err) {
setTimeout(()=> { console.log("C");
res() }, 3000)
})
return myProm;
});
myProm.then( () => { console.log("B") });
How do I proceed? What's the best way to chain two promises together so that the returned Promise obj from one .then needs to get resolved before we can execute the next then.
In this scenario, the output I'd like to have would be A C B
then returns a promise that resolves when the indicated function has run and the value it returned has resolved (this is a slight oversimplification, but sufficient for the task here).
Therefore, to chain a promise on the result of a then. Just tack on another .then:
var test = new Promise(function (res, err) { setTimeout(res, 3000) })
test.then( () => { console.log("A") });
test
.then( () => {
return new Promise(function(res, err) {
setTimeout(()=> { console.log("C"); res() }, 3000);
});
})
.then( () => { console.log("B") });
Each time you call .then, you create a new Promise that resolves when the Promise returned by that .then resolves. You should assign the result of the myProm-containing .then to a variable, and then call .then on that variable:
var test = new Promise(function (res, err) { setTimeout(res, 500) })
var myProm;
test.then( () => { console.log("A") })
.then( () => {
myProm = new Promise(function(res, err) {
setTimeout(()=> { console.log("C");
res() }, 500)
})
return myProm;
})
.then( () => { console.log("B") });
Most of the time when using Promises, you should be chaining .thens like this. Only do prom.then(...) ... prom.then(...) when you want to initialize two completely separate asynchronous operations when the prom resolves.
I have the following function:
function JSON_to_buffer(json) {
let buff = Buffer.from(json);
if ( json.length < constants.min_draft_size_for_compression) {
return buff;
}
return zlib.deflate(buff, (err, buffer) => {
if (!err) {
return buffer;
} else {
return BPromise.reject(new VError({
name: 'BufferError',
}, err));
}
});
}
I want to be able to run this but have it wait if it goes to the unzip call. I'm currently calling this within a promise chain and it's going back to the chain without waiting for this and returns after the previous promise chain has completed.
You can put that logic into a Promise along with an async function
function JSON_to_buffer(json) {
return new Promise(function (resolve, reject) {
let buff = Buffer.from(json);
if (json.length < constants.min_draft_size_for_compression) {
return resolve(buff);
}
zlib.deflate(buff, (err, buffer) => {
if (!err) {
resolve(buffer);
} else {
reject(err);
/*return BPromise.reject(new VError({
name: 'BufferError',
}, ));*/
}
});
});
}
async function main() {
try {
let buffer = await JSON_to_buffer(myJSON);
} catch (e) {
console.log(e.message);
}
}
I am testing a conditional sequence of three async/await functions ( functionA, functionB, functionC) in a task
however when I execute it, stating that the first functionA should not pass,
1 - I don't get the expected functionA failed message
2 - how should I handle errors to stop the sequence when any function is not passing ?
thanks for feedback
console.log
functionB: functionB passed
functionC: functionC passed
task ended
ES6 js
async function functionA(duration, shouldPass) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (shouldPass) {
resolve('functionA passed');
} else {
reject(Error('functionA failed'));
}
}, duration);
});
}
async function functionB(duration, shouldPass) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (shouldPass) {
resolve('functionB passed');
} else {
reject(Error('functionB failed'));
}
}, duration);
});
}
async function functionC(duration, shouldPass) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (shouldPass) {
resolve('functionC passed');
} else {
reject(Error('functionC failed'));
}
}, duration);
});
}
async function executeAsyncTask(condition1, condition2, condition3) {
let resultFunctionA = true
if (condition1) {
resultFunctionA = await functionA(3000, true)
console.log('functionA: ', resultFunctionA)
}
let resultFunctionB = true
if (resultFunctionA && condition2) {
resultFunctionB = await functionB(3000, true)
console.log('functionB: ', resultFunctionB)
}
let resultFunctionC = true
if (resultFunctionB && condition3) {
resultFunctionC = await functionC(3000, true)
console.log('functionC: ', resultFunctionC)
}
console.log('task ended')
}
// running task with condition1, condition2, condition3 parameters
executeAsyncTask(false, true, true)
1 - I don't get the expected functionA failed message
Because you are not calling functionA due to your condition1 being false.
2 - how should I handle errors to stop the sequence when any function
is not passing ?
Wrap it in a try catch block. Modified code to tailor what you are asking for.
Here's the assert from this great article: https://blog.patricktriest.com/what-is-async-await-why-should-you-care/
Here, we've wrapped the entire operation within a normal try/catch
block. This way, we can throw and catch errors from synchronous code
and asynchronous code in the exact same way. Much simpler.
async function functionA(duration, shouldPass) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (shouldPass) {
resolve('functionA passed');
} else {
reject(Error('functionA failed'));
}
}, duration);
});
}
async function functionB(duration, shouldPass) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (shouldPass) {
resolve('functionB passed');
} else {
reject(Error('functionB failed'));
}
}, duration);
});
}
async function functionC(duration, shouldPass) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (shouldPass) {
resolve('functionC passed');
} else {
reject(Error('functionC failed'));
}
}, duration);
});
}
async function executeAsyncTask(condition1, condition2, condition3) {
try {
let resultFunctionA = await functionA(3000, condition1)
console.log('functionA: ', resultFunctionA)
let resultFunctionB = await functionB(3000, condition2)
console.log('functionB: ', resultFunctionB)
let resultFunctionC = await functionC(3000, condition3)
console.log('functionC: ', resultFunctionC)
console.log('task ended')
} catch (err) {
console.error(err.message)
}
}
// running task with condition1, condition2, condition3 parameters
executeAsyncTask(false, true, true)
Why are you return Promise in async function. When you write async JS will wrapped your function in Promise.
Well all your function returns Promise it means that you have to use 2 times async