I will only review your algorithm. You could have get rid of randomness and rely on an exact procedure. Below, is my take on your problem:
<!DOCTYPE html>
<html>
<head>
<title>Letter permutations</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<script>
const str = "ABCDE";
function swap(arr, i, j) {
const temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
function loadPermutation(letters, indices) {
const permutation = [];
for (let i = 0; i < indices.length; ++i) {
permutation.push(letters[indices[i]]);
}
return permutation;
}
function generateNextPemutation(letters, indices) {
let i = indices.length - 2;
while (i >= 0 && indices[i] > indices[i + 1]) {
--i;
}
if (i === -1) {
return null;
}
let j = i + 1;
let min = indices[j];
let minIndex = j;
while (j < indices.length) {
if (indices[i] < indices[j] && indices[j] < min) {
min = indices[j];
minIndex = j;
}
++j;
}
swap(indices, i, minIndex);
++i;
j = indices.length - 1;
while (i < j) {
swap(indices, i++, j--);
}
return loadPermutation(letters, indices);
}
function getPermutations(letters) {
const indices = [];
// Set the initial indices:
for (let i = 0; i < letters.length; ++i) {
indices.push(i);
}
const permutations = [];
permutations.push(letters.split("")); // Initial permutation.
let letterPermutation;
while ((letterPermutation = generateNextPemutation(letters, indices)) !== null) {
permutations.push(letterPermutation);
}
const filter = new Set();
permutations.forEach((element, index, array) => {
filter.add(element.join(""));
});
return [...filter];
}
let ta = Date.now();
const crOutput = getPermutations(str);
let tb = Date.now();
console.log("coderodde's version:", (tb - ta), "milliseconds.");
console.log("coderodde's output", crOutput);
function getRandom(min, max) {
const minCeiled = Math.ceil(min);
const maxFloored = Math.floor(max);
return Math.floor(Math.random() * (maxFloored - minCeiled) + minCeiled);
}
function factorial(m) {
let num = 1;
for (let i = 1; i <= m; i++) {
num = num * i;
}
return num;
}
function check(A, B) {
for (let i = 0; i < A.length; i++) {
let a = 0;
for (let j = 0; j < A[i].length; j++) {
if (A[i][j] !== B[j]) {
a++;
}
// Use === instead of ==
if (a === B.length) {
return false; // <- forgot ;
}
}
}
return true;
}
function getCombinations(A) {
let x = A.length;
let B = [];
while (B.length < factorial(x)) {
let Y = [];
for (let i = 0; i < x; i++) {
// const instead of let:
const a = getRandom(0, (x));
if (!Y.includes(A[a])) { // <- !Y.include(A[a]) instead of .. == false!
Y.push(A[a]);
} else {
// i = i - 1;
--i; // <- simpler.
}
}
if (check(B, Y)) {
B.push(Y.join(""));
}
}
return B;
}
ta = Date.now();
const opResult = getCombinations(str);
tb = Date.now();
console.log("OP's version:", (tb - ta), "milliseconds.");
console.log("OP's output:", opResult);
</script>
</body>
</html>
Typical output
I have assembled this demo. It produces the following output:

Code review
I have embedded a couple of advices below:
function check(A, B) {
for (let i = 0; i < A.length; i++) {
let a = 0;
for (let j = 0; j < A[i].length; j++) {
if (A[i][j] !== B[j]) {
a++;
}
// Use === instead of ==
if (a === B.length) {
return false; // <- forgot ;
}
}
}
return true;
}
function getCombinations(A) {
let x = A.length;
let B = [];
while (B.length < factorial(x)) {
let Y = [];
for (let i = 0; i < x; i++) {
// const instead of let:
const a = getRandom(0, (x));
if (!Y.includes(A[a])) { // <- !Y.include(A[a]) instead of .. == false!
Y.push(A[a]);
} else {
// i = i - 1;
--i; // <- simpler.
}
}
if (check(B, Y)) {
B.push(Y.join(""));
}
}
return B;
}
Advices
Advice I (Terminology)
Actually, you are not computing combinations, but rather \$n\$-permutations.
Advices II (Superfluous vertical space)
Occasionally, you use 2 empty lines to separate code. Use 1.
Outro
So why is your random sampling slower? The reason is: towards the end of random generation of yet not visited permutations the probability of getting not yet included sample goes towards \$0\$ and thus involves more and more trials.