Before ES2019, array sorting in Javascript was not guaranteed to be stable. In this lesson, we'll learn what stable sorting is by emulating stable sorting in an older version of Node. Then, we'll learn how and when stable sorting matters. Finally, we'll use nvm to switch between an older version of Node and a newer version and compare how each version deals with sorting.
You can find installation instructions for nvm here. Stable sorting was adding to v8 v7.0 (Chrome 70 and Node 11), as noted in this blog post
Instructor: [00:00] Here we have our Nuxt.js application. It's printing out student averages. What's cool about Nuxt.js is that it's an isomorphic framework. That is, it will render new components server-side. Then once the page loads, it will render them client-side, again using the same JavaScript.
[00:18] However, this introduces an interesting wrinkle as the browser may be a different version of JavaScript, in this case Chrome, from the version of JavaScript the server is running. In this case, we are currently running Node 8.9.3.
[00:32] In our application, that has an interesting effect. If I reload the page, you'll see the names are sorted differently, Fernie appearing first. Once the JavaScript fully loads and runs client-side, Alicia will appear first.
[00:45] The reason this happens is that old versions of Node didn't have stable sorting. Stable sorting means that given two elements that are being sorted with equal sort values, the item that comes first in the input array should match the order of the item that comes in the output array.
[01:02] In this case, if Alicia and Bobby and all these students have the same averages and we're sorting by average, Alicia should come before Bobby in the output array, because she's first in the input array.
[01:13] To see how we can mimic stable sorting in older versions of Node, let's see how index.vue passes the scores.json data to scores.vue. As we can see here inside our asyncData function, we are reading scores.json, parsing it, and returning it to the asyncData function, which then gets used to render in our template.
[01:34] In this case the scores property is bound to the scores property of the input and gets passed to the scores component. The scores component will look through each record in its sorted property and print out record.student, record.average, record.grade, and record.teachers, where a record is an element in the sorted array.
[01:55] Sorted is a computed property. The sorted computed property is built by mapping the current records and transforming them and then sorting them, taking the difference of the average of the two students.
[02:07] In this case, because all students have the same average, we've hit the stable sorting problem. In order to fix this in older versions of Node, we could iterate over the records before sorting them and add a index property to the record and, when sorting them, first detect if A.average = B.average. Then return A.index - B.index and let the index be the tiebreaker.
[02:43] If we refresh our code again, we'll see that there's now no flash. Alicia appears before Bobby. Thankfully, later versions of Node solve this by having sort be stable right out of the box.
[02:56] In order to see this, I'm now going to upgrade Node. To do so, I use a program called NVM. NVM is a Node Version Manager which you can get from Homebrew or any other way to install software. You type something like NVM use 11 to install and use the latest version of Node, Node 11.
[03:12] If I type node --version now, it'll say version 11.14. If I go back to my Nuxt development server and I recompile and wait for it to build, I can now remove all that additional code I just added in. Wait for it to compile. Refresh the page. If I refresh again, I now see it prints out Alicia right away.
Not a big deal, however, at the end with node 11, there was a wrinkle.
I had to run npm audit fix
and the lowest version of node that would work was 11.15.0
other than that, things worked as expected. I didn't get the sorting flash from server to client as shown in the video, not an issue, just sayin'. First time using Nuxt.js, I'm really liking this.
Nice. As with optional catch binding in the previous video, I didn't know this was an issue, but now that I do, it's good to see that it's fixed!
I'm guessing the stable sorting added to the newer version of Node preceded ES2019 and is just some custom code similar to yours.
I'm guessing the stable sorting added to the newer version of Node preceded ES2019 and is just some custom code similar to yours.
Firefox and Safari had already had stable sorting for a while, although it was never part of the spec. Once v8, the JS engine powering Chrome and Node agreed to implement TimSort (yes, TimSort, not Timesort), which happened to be stable, finally all major implementations had stable sorting so it was added to the spec to gaurantee this property in any future implementation.
What is used as criteria when stable sort is not available and the average in the example is the same?
Hi João,
In practice, this isn't really a question of "what criteria is used" but rather "is the algorithm stable". That is, some sort algorithms can swap equal entries in certain circumstances (usually as a speed boost or way to keep the algorithm simple) while others don't.
ES2020 fixes this by saying that the chosen sort algorithm must be a stable one.
More than your well explained lesson here, I highly appreciated that you took time to explain your tool ( here nvm ) for those who didn't yet encounter it 👍