Spread operator was introduced with JavaScript ES6 along with other great features, but with great power comes the great responsibility. Mostly it is used to create a new reference to object or an array, though it only copies one level deep it's pretty useful especially where we cannot mutate object like React or Redux state, though we are not creating a whole new object, it gets the work done.
Great! What's the issue then? Enough talk let's write some code, We will be using a user array for this purpose and will create a map of active users. Let's define a simple User interface before jumping to real problem.
interface IUser {
active: boolean;
name: string;
id: string;
}
const users = []; // 10,000 users
Case 1
const activeUsers = users.reduce((acc, user) => {
if (user.active) {
return { ...acc, [user.id]: user };
}
return acc;
}, {});
Case 2
let activeUsers = {};
users.forEach((user) => {
if (user.active) {
result[user.id] = user;
}
});
Case 3
const a = users.filter((user) => user.active).map((user) => [user.id, user]);
const activeUsers = Object.fromEntries(a);
Can you arrange according their performance? from best to worst.
Check actual stats!
### Result
- Case 2
- Case 3 (~63% slow)
- Case 1 (~86% slow)
Checkout all test cases here: JS Bench
Let's dive in
No surprise case 2 was fasted, just plain loop with simple key value addition.
Case 3 was expected to be slow as it has to iterate the array twice that should slow it down and now we have an idea by what margin so avoid it.
Case 1 was not expected to be this slow as it's similar to case one with builtin method, there is one thing which might be slowing it down, reduce
internal implementation!
Nope, it's the spread operator, in general it's slower then adding a key-pair to object but that doesn't mean avoid it just use it only if required. In the case 1 anyway we will get a new object
from the reduce
using spread operator is totally unnecessary. Change it to
const activeUsers = users.reduce((acc, user) => {
if (user.active) {
acc[user.id] = user;
}
return acc;
}, {});
and it is almost at par with forEach
one, 1% slower.
We might have developed a habit of always using spread operator to avoid uncalled bugs in daily life especially with React and it might not be degrading the performance much but it can, in some cases like this one, so let's remember this, might come handy one it.
Top comments (2)
So true. Spreading, destructuring, reduce all are amazing tools. However as someone wise once said "It depends".
Always ensure to use right tool for right job. I've goofed up similarly & wrote an article (Reduce its not my friend anymore) about the same long back.
Wonderful way to say that all that glitters is not gold.
Keep doing great
Cheers 👍
Thanks for sharing. Case 1 is square complexity thus it's the slowest. Case 3 is linear but creates a lot of intermediate arrays.