async function sort(arr, comparator) {
        // undefined inputs always return undefined
        if (typeof arr === 'undefined') {
            return undefined;
        }

        if (arr.length <= 1) {
            return arr;
        }

        var comp;
        if (typeof comparator === 'undefined') {
            // inject a default comparator - only works for numeric or string arrays
            if (!isArrayOfNumbers(arr) && !isArrayOfStrings(arr)) {
                throw {
                    stack: (new Error()).stack,
                    code: "D3070",
                    index: 1
                };
            }

            comp = async function (a, b) {
                return a > b;
            };
        } else {
            // for internal usage of functionSort (i.e. order-by syntax)
            comp = comparator;
        }

        var merge = async function (l, r) {
            var merge_iter = async function (result, left, right) {
                if (left.length === 0) {
                    Array.prototype.push.apply(result, right);
                } else if (right.length === 0) {
                    Array.prototype.push.apply(result, left);
                } else if (await comp(left[0], right[0])) { // invoke the comparator function
                    // if it returns true - swap left and right
                    result.push(right[0]);
                    await merge_iter(result, left, right.slice(1));
                } else {
                    // otherwise keep the same order
                    result.push(left[0]);
                    await merge_iter(result, left.slice(1), right);
                }
            };
            var merged = [];
            await merge_iter(merged, l, r);
            return merged;
        };

        var msort = async function (array) {
            if (!Array.isArray(array) || array.length <= 1) {
                return array;
            } else {
                var middle = Math.floor(array.length / 2);
                var left = array.slice(0, middle);
                var right = array.slice(middle);
                left = await msort(left);
                right = await msort(right);
                return await merge(left, right);
            }
        };

        var result = await msort(arr);

        return result;
    }
Implements the merge sort (stable) with optional comparator function

@param {Array} arr - the array to sort
@param {*} comparator - comparator function
@returns {Array} - sorted array