Linking functions with Promises in React - javascript

I've been fighting with updating the state in Reactjs in the correct order for the past few days which made me realise I need to handle my asynchronous functions properly. Unfortunately, it turns out I don't fully understand Promise() either. I am struggling to make the Promise chain work correctly as my third function is never called in the example below.
componentDidMount() {
this.mockOne()
.then(this.mockTwo())
.then((successMessage) => {
console.log('successMessage: ', successMessage);
this.mockThree()
});
}
mockOne() {
return new Promise((resolve, reject) => {
console.log('mockOne')
})
}
mockTwo() {
return new Promise((resolve, reject) => {
setTimeout(function() {
console.log('mockTwo')
}, 2000)
})
.catch(err => console.log('There was an error in mockTwo:' + err));
}
mockThree() {
return new Promise((resolve, reject) => {
console.log('mockThree')
})
}
console output
I've tried the instructions in the MDC but either mockThree() is called immediately before mockTwo() has a chance to respond or mockThree() isn't called at all.
Any help to get this working will be greatly appreciated.
The answer provided worked perfectly until I tried to chain a few more asynchronous functions. Can anyone help me understand why my first function causes the workflow to pause but the next three functions are completed immediately please?
componentDidMount() {
this.mockOne()
.then(successMessage => {
this.mockTwo();
})
.then(successMessage => {
this.mockThree();
})
.then(successMessage => {
this.mockFour();
});
}
mockOne() {
return new Promise((resolve, reject) => {
console.log("mockOne");
setTimeout(function() {
resolve("Test success message");
}, 2000);
}).catch(err => console.log("There was an error in mockOne:" + err));
}
mockTwo() {
return new Promise((resolve, reject) => {
console.log("mockTwo");
setTimeout(function() {
resolve("Test success message");
}, 2000);
}).catch(err => console.log("There was an error in mockTwo:" + err));
}
mockThree() {
return new Promise((resolve, reject) => {
console.log("mockThree");
setTimeout(function() {
resolve("Test success message");
}, 2000);
}).catch(err => console.log("There was an error in mockThree:" + err));
}
mockFour() {
return new Promise((resolve, reject) => {
console.log("mockFour");
setTimeout(function() {
resolve("Test success message");
}, 2000);
}).catch(err => console.log("There was an error in mockFour:" + err));
}

You have to call the resolve function for the promise to become fulfilled. You also need to make sure you are not invoking this.mockTwo() straight away, but instead just give the function this.mockTwo to then.
class App extends React.Component {
componentDidMount() {
this.mockOne()
.then(this.mockTwo)
.then(successMessage => {
console.log("successMessage: ", successMessage);
this.mockThree();
});
}
mockOne() {
return new Promise((resolve, reject) => {
console.log("mockOne");
resolve();
});
}
mockTwo() {
return new Promise((resolve, reject) => {
console.log("mockTwo");
setTimeout(function() {
resolve("Test success message");
}, 2000);
}).catch(err => console.log("There was an error in mockTwo:" + err));
}
mockThree() {
return new Promise((resolve, reject) => {
console.log("mockThree");
resolve();
});
}
render() {
return null;
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

I figured out the answer to my expanded (edited) question of why the chain wasn't working as expected. All I had to do was chain the functions properly, as below:
this.mockOne()
.then(successMessage => {
this.mockTwo()
.then(successMessage => {
this.mockThree()
.then(successMessage => {
this.mockFour()
})
})
})

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();

Promise resolution returns undefined value but i have returned with resolve [duplicate]

This question already has answers here:
When should I use a return statement in ES6 arrow functions
(6 answers)
Closed 2 years ago.
console.log("Before");
getUser(1)
.then((user) => getRepositories(user.gitHubUsername))
.then((repos) => {
getCommits(repos[0]);
})
.then((commits) => {
console.log("commits: ", commits);
})
.catch((err) => console.log("Error: ", err.message));
console.log("After");
function getUser(id) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("Reading a user from a database...");
resolve({
id: id,
gitHubUsername: "mosh"
});
}, 2000);
});
}
function getRepositories(username) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("Calling GitHub API...");
resolve(["repo1", "repo2", "repo3"]);
}, 2000);
});
}
function getCommits(repo) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("Calling GitHub API...");
resolve("commit");
}, 2000);
});
}
now here evey function which is chained is contains a promise which is resolving something i.e username, array etc. but when i run this code on the console it displays commnits : undefined
you can see it in this attached image
You missed the return:
console.log("Before");
getUser(1)
.then((user) => getRepositories(user.gitHubUsername))
.then((repos) => {
return getCommits(repos[0]);
})
.then((commits) => {
console.log("commits: ", commits);
})
.catch((err) => console.log("Error: ", err.message));
console.log("After");
function getUser(id) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("Reading a user from a database...");
resolve({
id: id,
gitHubUsername: "mosh"
});
}, 2000);
});
}
function getRepositories(username) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("Calling GitHub API...");
resolve(["repo1", "repo2", "repo3"]);
}, 2000);
});
}
function getCommits(repo) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("Calling GitHub API...");
resolve("commit");
}, 2000);
});
}

confused with .then() in promises

I'm new to js and I'm learning promises. I came up with this code which will print the resolved values from every function and will call new functions using .then
function login() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({username : 'default'})
}, 1000)
})
}
function getVideos() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(['vid1', 'vid2'])
},1000)
})
}
function getDesc() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('desc')
}, 1000)
})
}
const test = login()
test.then(res => {
console.log(res)
getVideos()
})
.then(res => {
console.log(res)
getDesc()
})
.then(res => console.log(res))
But, I'm not getting the expected result, I thought all the statements in .then() needed to be executed and resolved to continue to the next .then() statement. But clearly this is not the case here as I'm getting the following as the output -
{ username: 'default' }
undefined
undefined
But I expected the output to be similar to this -
{username : 'default}
['vid1', 'vid2']
desc
pls, point where I'm going wrong here. Any help is appreciated, thanks a lot
You need to add return to inside your chains when you're calling those functions. For example:
function login() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({username : 'default'})
}, 1000)
})
}
function getVideos() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(['vid1', 'vid2'])
},1000)
})
}
function getDesc() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('desc')
}, 1000)
})
}
const test = login()
test.then(res => {
console.log(res)
return getVideos()
})
.then(res => {
console.log(res)
return getDesc()
})
.then(res => console.log(res))
This is a good guide: https://javascript.info/promise-chaining
Make a couple of very minor changes:
const test = login()
test.then(res => {
console.log(res)
return getVideos()
})
.then(res => {
console.log(res)
return getDesc()
})
.then(res => console.log(res))
To chain promises together, you need to return the promises at each step. As it is you're implicitly returning undefined which is not a promise.

Is logging to the console the same thing that is resolved redundant?

I have a program that makes the computer simulate multiple chores at once using asynchronous JavaScript Promises. I decided to start small and focus on washing the dishes. Basically, my code has two files - a library for returning a new instance of the Promise object and an app.js which calls these functions with .then() and .catch().
This is what the functions in library.js looks like.
let washDishes = ({soap}) => {
return new Promise ((resolve, reject) => {
setTimeout(() => {
if (soap) {
console.log('Status: Clean Dishes'.blue)
resolve('clean dishes');
}
else {
console.log('Status: Dirty Dishes'.blue);
reject('dirty dishes');
}
}, 1000)
})
};
let addSoap = () => {
return new Promise ((resolve) => {
setTimeout(() => {
console.log('Status: Soap Added'.blue)
resolve('soap added');
}, 1000)
})
};
let emptyDishwasher = () => {
return new Promise ((resolve) => {
setTimeout(() => {
console.log('Status: Dishwasher Emptied'.blue)
resolve('dishes put away')
}, 1000);
})
}
In the above, I return a new promise, logging the status and resolving the same text after 1 second. Is it redundant to resolve() and console.log() at the same thing?
If I don't resolve, it won't move on. If I don't log, it doesn't show what is happening.
This is the bulk of my app.js code:
console.log("Doing chores...");
const cleanDishes = washDishes({soap: true})
.then(function(resolvedValue) {
emptyDishwasher(resolvedValue);
})
.catch(function(rejectedValue) {
addSoap(rejectedValue);
});
Putting the console.log() statements here will result in the console printing
Promise <pending>
How should I restructure my code to stop this redundancy, maintaining the fact that I am practicing Promises?
You can make your code more DRY by factoring out repeated parts in helper functions:
function withStatusLog(fn) {
return function(val) {
console.log(('Status: ' + val[0].toUpperCase() + val.slice(1)).blue);
return fn(val);
};
}
function newDelayedStatusPromise(executor) {
return new Promise((resolve, reject) => {
setTimeout(() => {
executor(withStatusLog(resolve), withStatusLog(reject))
}, 1000);
});
}
function washDishes({soap}) {
return newDelayedStatusPromise((resolveStatus, rejectStatus) => {
if (soap) {
resolveStatus('clean dishes');
} else {
rejectStatus('dirty dishes');
}
})
}
function addSoap() {
return newDelayedStatusPromise(resolveStatus => {
resolveStatus('soap added');
});
}
function emptyDishwasher() {
return newDelayedStatusPromise(resolveStatus => {
resolveStatus('dishes put away'); // or 'dishwasher emptied'?
});
}

About Node.js Promise then and return?

I'm confused about Promise!
I use Promise then without return like this:
new Promise((resolve, reject) => {
resolve("1");
}).then((v1) => {
console.log("v1");
new Promise((resolve, reject) => {
//Time-consuming operation, for example: get data from database;
setTimeout(() => {
resolve(2)
}, 3000);
}).then((v11) => {
console.log("v11");
})
}).then((v2) => {
console.log("v2")
});
I get this result v1 v2 v11.
Then, I use another way of writing, Like below:
new Promise((resolve, reject) => {
resolve("1");
}).then((v1) => {
console.log("v1");
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2)
}, 3000)
}).then((v11) => {
console.log("v11");
})
}).then((v2) => {
console.log("v2")
});
I get another result v1 v11 v2.
Maybe, There is another case:
new Promise((resolve, reject) => {
resolve("1");
}).then((v1) => {
console.log("v1");
return new Promise((resolve, reject) => {
setTimeout(() => {resolve(2)}, 3000)
}).then((v11) => {
console.log("v11");
return new Promise((resolve, reject) => {
setTimeout(() => {resolve(2)}, 4000)
}).then(() => {
console.log("v12")
})
})
}).then((v2) => {
console.log("v2")
});
I get this result v1 v11 v12 v2
I can't understand the second return I want to know why I get this result?
It will be easier to understand the control flow if you actually print the values of the resolved promises and not only the names of the variables:
Version 1
new Promise((resolve, reject) => {
resolve("1");
}).then((v1) => {
console.log("v1:", v1);
new Promise((resolve, reject) => {
//Time-consuming operation, for example: get data from database;
setTimeout(() => {
resolve(2)
}, 3000);
}).then((v11) => {
console.log("v11:", v11);
})
}).then((v2) => {
console.log("v2:", v2)
});
Version 2
new Promise((resolve, reject) => {
resolve("1");
}).then((v1) => {
console.log("v1:", v1);
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2)
}, 3000)
}).then((v11) => {
console.log("v11:", v11);
})
}).then((v2) => {
console.log("v2:", v2)
});
Version 3
new Promise((resolve, reject) => {
resolve("1");
}).then((v1) => {
console.log("v1:", v1);
return new Promise((resolve, reject) => {
setTimeout(() => {resolve(2)}, 3000)
}).then((v11) => {
console.log("v11:", v11);
return new Promise((resolve, reject) => {
setTimeout(() => {resolve(2)}, 4000)
}).then((v12) => {
console.log("v12:", v12)
})
})
}).then((v2) => {
console.log("v2:", v2)
});
Now you can see what gets passed to the callbacks:
Result 1
v1: 1
v2: undefined
v11: 2
Result 2
v1: 1
v11: 2
v2: undefined
Result 3
v1: 1
v11: 2
v12: 2
v2: undefined
Explanation
As you can see when in the .then() handlers you don't return a promise, it acts as if you returned an already resolved promise with value undefined - like if you did:
return Promise.resolve(undefined);
and thus the next .then() handler can be called immediately.
If, on the other hand, you return a promise that is not resolved yet, then the next .then() handler will not be invoked immediately but only after that returned promise gets resolved.
And that explains the order of execution that is different when you don't return a promise - and what happens is as if an already resolved promise got returned implicitly for you.
function one() {
return new Promise((resolve,reject) => {
setTimeout(function () {
console.log("one 1 ");
resolve('one one');
}, 2000);
});
}
function two() {
return new Promise((resolve,reject) => {
setTimeout(function () {
console.log("two 2 ");
resolve('two two');
}, 10000);
});
}
function three(){
setTimeout(function () {
console.log("three 3 ");
}, 5000);
}
one().then((msg) => {
console.log('one : ', msg);
return two();
}).then((msg) => {
console.log('two :', msg);
return three();
}).then((msg) => {
console.log('three :', msg);
})
.catch((error) => {
console.error('Something bad happened:', error.toString());
});
console three show undefined because three not parse resolve

Categories