Use a seeded random number generator
Math.random()
generates a new random number every time it's called. It's useful when you don't need cryptographically secure randomness.
But it generates a completely new number every time; therefore it can not be repeated.
Repeating numbers
Why is that a problem?
For simple use cases, a sufficiently random number is all you need. Rolling a dice, generating a UUID, shuffling an Array.
But as the application matures, that brings new challenges. Tests should be predictable, and sometimes you need reproducibility.
What if the user clicks on this button? If that would mean some consistency check to fail, disable the button.
This is when seeded random generators come into play.
Seeded random number generators
A seeded generator gets a seed
value, and use that to generate the stream of random numbers.
It's somewhat similar to a hash function. If you use the same seed, you get the same values and different ones for a different seed.
What is a good seed?
Anything that you also store, as that makes it predictable and reproducible.
It's tempting to use String(new Date())
, but that defeats the point.
On the other hand, there is no universally best seed, as it depends on your app.
Seeded random libs
Several libraries provide seeded random functions. The one I've used and prefer is seedrandom's Alea implementation.
To use it, import the module either via a <script>
tag or an import
, initialize with a seed
, which is a String, and it's ready to use: alea(seed)
.
To emulate Math.random
, use:
const random = alea(seed).double;
This gives a function that is similar to the built-in one.
To get predictable rolls of dice in an Array, get the randomness from this function:
const random = alea("123456789").double;
console.log(
Array(10).fill()
.map(() => Math.floor(random() * 6) + 1)
); // [2,1,1,2,3,5,5,5,1,6]