前端算法题

227 阅读5分钟

0.小浩算法


// 冒泡
const array = [23, 3, 12, 44, 42, 344];
function bubbleSort(arr) {
    const len = arr.length;
    for (let i = 0; i < len - 1; i++) {
        for (let j = 0; j < len - i - 1; j++) {
            if (arr[j] > arr[j + 1]) {
                const temp = arr[j + 1];
                arr[j + 1] = arr[j];
                arr[j] = temp;
            }
        }
    }
    return arr;
}
bubbleSort(array);

// 选择
function selectSort(arr) {
    const len = arr.length;
    let minIndex;
    let temp;
    for (let i = 0; i < len - 1; i++) {
        minIndex = i;
        for (let j = i + 1; j < len; j++) {
            if (arr[minIndex] > arr[j]) {
                minIndex = j;
            }
        }
        temp = arr[i];
        arr[i] = arr[minIndex];
        arr[minIndex] = temp;
    }
    return arr;
}
selectSort(array);

// 插入
function insertSort(arr) {
    const len = arr.length;
    for (let i = 1; i < len; i++) {
        preIndex = i - 1;
        current = arr[i];
        while (preIndex >= 0 && arr[preIndex] > current) {
            arr[preIndex + 1] = arr[preIndex];
            preIndex--;
        }
        arr[preIndex + 1] = current;
    }
    return arr;
}
insertSort(array);

// 希尔
const aaaa = [23, 34, 2, 2, 13, 2, 45];
function insertion(arr) {
    if (arr === null || arr.length <= 1) {
        return arr;
    }
    const len = arr.length;
    for (let d = Math.floor(len / 2); d > 0; d = Math.floor(d / 2)) {
        for (let i = d; i < len; i++) {
            for (let j = i - d; j >= 0; j -= d) {
                if (arr[j] > arr[j + d]) {
                    const temp = arr[j + d];
                    arr[j + d] = arr[j];
                    arr[j] = temp;
                }
            }
        }
    }
    return arr;
}
insertion(aaaa);

// 归并
const aaaaa = [233, 3, 2, 2, 232, 23, 2432, 333];
function merge(left, right) {
    const result = [];
    const minIndex = Math.min(left.length, right.length);
    while (left.length && right.length) {
        if (left[0] <= right[0]) {
            result.push(left.shift());
        } else {
            result.push(right.shift());
        }
    }
    while (left.length) {
        result.push(left.shift());
    }
    while (right.length) {
        result.push(right.shift());
    }
    return result;
}

function mergeSort(arr) {
    if (arr === null || arr.length < 2) {
        return arr;
    }
    const middle = Math.floor(arr.length / 2);
    const left = arr.slice(0, middle);
    const right = arr.slice(middle);
    return merge(mergeSort(left), mergeSort(right));
}
mergeSort(aaaaa);

// 快速
function swap(A, i, j) {
    [A[i], A[j]] = [A[j], A[i]];
}

function partition(arr,left,right) {
    //const pivot = A[hi - 1];
    //let i = lo;
    //let j = hi - 2;
    //while (i !== j) {
    //    A[i] <= pivot ? i++ : swap(A, i, j--);
    //}
    //if (lo < hi - 2) {
    //    swap(A, j, hi - 1);
    //}
    //return j;
    var pivot = left,    // 设定基准值(pivot)
        index = pivot + 1;
    for (var i = index; i <= right; i++) {
        if (arr[i] < arr[pivot]) {
            swap(arr, i, index);
            index++;
        }        
    }
    swap(arr, pivot, index - 1);
    return index-1;
}

function qsort(A, lo = 0, hi = A.length) {
    if (hi - lo < 2) return null;
    const p = partition(A, lo, hi);
    qsort(A, lo, p);
    qsort(A, p + 1, hi);
    return A;
}
qsort([10, 80, 40, 32, 11, 31, 1, 3, 20]);

// 两个数组的交集(350)
function inter(arr1, arr2) {
    const obj = {};
    arr1.forEach((item) => {
        if (!obj[item]) {
            obj[item] = 1;
        } else {
            obj[item]++;
        }
    });
    const result = [];
    arr2.forEach((item) => {
        if (obj[item]) {
            result.push(item);
            obj[item]--;
        }
    });
    return result;
}
const intersect = new Set([4, 9, 4].filter((x) => new Set(9, 4, 9, 8, 4).has(x)));
console.log(intersect);
inter([4, 9, 4], [9, 4, 9, 8, 4]);

// 最长公共前缀
function longest(arr) {
    const point = arr.shift();
    let len = point.length;
    for (let j = 0; j < arr.length; j++) {
        for (let i = 0; i < point.length; i++) {
            if (arr[j][i] !== point[i]) {
                if (i < len) {
                    len = i;
                }
                break;
            }
        }
    }
    return point.substr(0, len);
}
longest(['flower', 'flow', 'flight']);

// 买卖股票的最佳时机(122)
function maxProfit(arr) {
    let result = 0;
    for (let i = 0; i < arr.length - 1; i++) {
        if (arr[i + 1] > arr[i]) {
            result += arr[i + 1] - arr[i];
        }
    }
    return result;
}
maxProfit([7, 1, 5, 3, 6, 4]);

// 反转数组
function reverse1(arr, i, j) {
    while (i < j) {
        [arr[i], arr[j]] = [arr[j], arr[i]];
        i++;
        j--;
    }
}
function reverseArr(arr, k) {
    k %= arr.length;
    if (arr.length < 2) {
        return arr;
    }
    reverse1(arr, 0, arr.length - 1);
    reverse1(arr, 0, k - 1);
    reverse1(arr, k, arr.length - 1);
    return arr;
}
reverseArr([1, 2, 3, 4, 5, 6, 7], 3);

// 原地删除
function spliceArr(arr, k) {
    for (let i = 0; i < arr.length; i++) {
        if (arr[i] === k) {
            [arr[i], arr[arr.length - 1]] = [arr[arr.length - 1], arr[i]];
            arr.length--;
            i--;
        }
    }
    return arr.length;
}
spliceArr([1, 2, 3, 4, 5, 6, 7], 3);

// 加一
function addArr(arr) {
    for (let i = arr.length - 1; i >= 0; i--) {
        if (arr[i] < 9) {
            arr[i] = arr[i] + 1;
            break;
        } else {
            arr[i] = 0;
        }
        if (i === 0) {
            arr.unshift(1);
        }
    }
    return arr;
}
addArr([9, 9, 8, 9]);

// 两数之和
function twoSum(arr, k) {
    const obj = {};
    for (let i = 0; i < arr.length; i++) {
        if (obj[k - arr[i]] === undefined) {
            obj[arr[i]] = i;
        } else {
            return [obj[k - arr[i]], i];
        }
    }
    return [];
}
twoSum([2, 7, 11, 15], 9);

// 三数之和
function threeSum(arr) {
    arr = arr.sort();
    const result = [];
    for (let i = 0; i < arr.length; i++) {
        // for(let j=i;j<arr.length;j++){

        // }
        let k = i + 1;
        let j = arr.length - 1;
        const target = 0 - arr[i];
        if (arr[i] <= 0) {
            if (i === 0 || arr[i] !== arr[i - 1]) {
                while (k < j) {
                    if (arr[k] + arr[j] === target) {
                        result.push([arr[i], arr[k], arr[j]]);
                        while (k < j && nums[k] === nums[k + 1]) k++;
                        while (k < j && nums[j] === nums[j - 1]) j--;
                        k++;
                        j--;
                    } else if (arr[j] + arr[k] < target) {
                        k++;
                    } else {
                        j--;
                    }
                }
            }
        }
    }
    return result;
}
threeSum([-1, 0, 1, 2, -1, -4]);

// Z 字形变换
function convert(s, numRows) {
    if (numRows === 1) {
        return s;
    }
    let down = true;
    const resultArr = [];
    let resultIndex = 0;
    for (let i = 0; i < s.length; i++) {
        resultArr[resultIndex] = (resultArr[resultIndex] ?? '') + s[i];
        if (i !== 0 && i % (numRows - 1) === 0) {
            down = !down;
        }
        resultIndex += down ? 1 : -1;
    }
    return resultArr.join('');
}
convert('LEETCODEISHIRING', 3);


// 删除链表的倒数第 N 个结点(19)
var removeNthFromEnd = function(head, n) {
    let prevNode = new ListNode(0);
    prevNode.next = head;
    let show =  prevNode;
    let fast =  prevNode;
    while(n--){
        fast = fast.next;
    }
    while(fast&&fast.next){
        show = show.next;
        fast = fast.next;
    }
    show.next = show.next.next;
    return prevNode.next;
};

// 21. 合并两个有序链表
var mergeTwoLists = function (l1, l2) {
    let prevNode = new ListNode(0);
    let result = prevNode;
    while (l1 && l2) {
        if (l1.val < l2.val) {
            prevNode.next = l1;
            l1 = l1.next;
        } else {
            prevNode.next = l2;
            l2 = l2.next;
        }
        prevNode = prevNode.next;
    }
    if (l1) {
        prevNode.next = l1;
    }
    if (l2) {
        prevNode.next = l2;
    }
    return result.next;
};

// 环形链表(141)
var hasCycle = function (head) {
    let slow = head;
    let fast = head;
    while (fast) {
        if (!fast.next) return false;
        slow = slow.next;
        fast = fast.next.next;
        if (slow === fast) return true;
    }
    return false;
};

//两数相加
var addTwoNumbers = function (l1, l2) {
    let prevNode = new ListNode(0);
    let result = prevNode;
    let k = 0;
    while (l1 || l2 || k) {
        let num1 = l1 ? l1.val : 0;
        let num2 = l2 ? l2.val : 0;
        let count = num1 + num2 + k;
        result.next = new ListNode(count % 10);
        result = result.next;
        l1 && (l1 = l1.next);
        l2 && (l2 = l2.next);
        k = count > 9 ? 1 : 0;
    }
    return prevNode.next;
};

// 最大子序和
var maxSubArray = function(nums) {
    if(nums.length<1){
        return 0;
    }
    let dp = [];
	dp[0] = nums[0];
    let max = dp[0];
    for(let i=1;i<nums.length;i++){
        dp[i] = Math.max(dp[i-1]+nums[i],nums[i]);
    if(dp[i]>max){
        max = dp[i];
    }
    }
   
    return max;
};

// 300. 最长递增子序列
var lengthOfLIS = function (nums) {
    let dp = new Array(nums.length).fill(1);
    if (nums.length < 1) {
        return 0;
    }
    for (let i = 1; i < nums.length; i++) {
        for (let j = 0; j < i; j++) {
            if (nums[i] > nums[j]) {
                dp[i] = Math.max(dp[i], dp[j] + 1);
            }
        }
    }
    return Math.max(...dp);
};

//120. 三角形最小路径和
var minimumTotal = function(arr) {
    if(arr.length<1){
        return 0;
    }
   let dp = Array.from(Array(arr.length),(item,index)=>new Array(index+1));
   dp[0][0] = arr[0][0];
   for(let i=1;i<arr.length;i++){
       for(let j=0;j<arr[i].length;j++){
           if(j===0){
               dp[i][j] = dp[i-1][j]+arr[i][j];
           }else if(j===arr[i].length-1){
               dp[i][j] = dp[i-1][j-1]+arr[i][j];
           }else{
               dp[i][j] = Math.min(dp[i-1][j-1],dp[i-1][j])+arr[i][j];
           }
       }
   }
   return Math.min(...dp[dp.length-1])
};

//64. 最小路径和
var minPathSum = function(grid) {
  let rows = grid.length;
    if(rows<1){
        return 0;
    }
    let cols = grid[0].length;
    if(cols<1){
        return 0;
    }
    let dp = Array(rows).fill(Array(cols).fill(0));
    
    for(let i=0;i<rows;i++){
        for(let j=0;j<cols;j++){
            if(i===0&&j===0){
                dp[0][0] = grid[0][0];
            }else if(i===0){
                dp[i][j] = dp[i][j-1]+grid[i][j];
            }else if(j===0){
                dp[i][j] = dp[i-1][j]+grid[i][j];
            }else{
                dp[i][j] = Math.min(dp[i-1][j]+grid[i][j],dp[i][j-1]+grid[i][j]);
            }
        }
    }
    return dp[rows-1][cols-1]
};

// 198. 打家劫舍
var rob = function(nums) {
   let dp = [];
    let len = nums.length;
    if(len<1){
        return 0;
    }else if(len===1){
        return nums[0];
    }else if(len===2){
        return Math.max(nums[0],nums[1])
    }
    dp[0] = nums[0];
    dp[1] = Math.max(nums[0],nums[1]);
    for(let i=2;i<len;i++){
        dp[i] = Math.max(dp[i-2]+nums[i],dp[i-1]);
    }
    return Math.max(...dp);
};

//344. 反转字符串
var reverseString = function(s) {
    if(s.length<=1){
        return s;
    }
    let l = 0;
    let r = s.length-1;
    while(l<r){
        let temp = s[l];
        s[l] = s[r];
        s[r] = temp;
        l++;
        r--;
    }
    return s;
};

//387. 字符串中的第一个唯一字符
var firstUniqChar = function(s) {
    let obj = {};
    for(let i=0;i<s.length;i++){
        if(obj[s[i]]){
            obj[s[i]]++;
        }else{
            obj[s[i]] = 1;
        }
    }
    let newArr = Object.keys(obj);
    console.log(newArr,obj);
    for(let i=0;i<newArr.length;i++){
        if(obj[newArr[i]]===1){
            return s.indexOf(newArr[i])
        }
    }
    return -1;
};

//实现 strStr()
var strStr = function(str, target) {
    if(target===''){
        return 0;
    }
     for (let i = 0; i < str.length; i++) {
        if (str[i] === target[0]) {
            if (str.substr(i, target.length) === target) {
                return i;
            }
        }
    }
    return -1;
};

// 剑指 Offer 17. 打印从1到最大的n位数
var printNumbers = function(n) {
    let l = 0;
    while(n){
        n--;
        l=10*l+9;
    }
    let result = [];
    for(let i=1;i<=l;i++){
        result.push(i);
    }
    return result;
};


// 第125题:验证回文串
var isPalindrome = function(str) {
    str = str.replace(/[^\w]|_/g,'').toLowerCase();
if (str.length <= 1) return true;
    while (str.length >= 2) {
        if (str.substr(0, 1) !== str.substr(str.length - 1)) {
            return false;
        }
        str = str.substring(1, str.length - 1);
    }
    return true;
};

// 第796题:旋转字符串
// 给定两个字符串, A 和 B。A 的旋转操作就是将 A 最左边的字符移动到最右边。例如, 若 A = 'abcde',
// 在移动一次之后结果就是'bcdea' 。如果在若干次旋转操作之后,A 能变成B,那么返回True。
var rotateString = function (a, b) {
    a = a + a;
    if (a.indexOf(b) > -1 && a.length / 2 === b.length) {
        return true;
    }
    return false;
};

// 最后一个单词的长度(58)
var lengthOfLastWord = function(words) {
    let result =words.match(/\s*(\w+)\s*$/i);
    if(result){
        result = result[1].length;
    }else{
        result = 0;
    }
    console.log(result);
    return result;
};


//层次遍历与BFS(102)
var levelOrder = function(root) {
    return dfs(root,0,[])
};
function dfs(root,level,res){
    if(!root){
        return res;
    }
    if(res.length===level){
        res.push([root.val])
    }else{
        res[level].push(root.val);
    }
    res = dfs(root.left,level+1,res);
    res = dfs(root.right,level+1,res);
    return res;
}

// 第98题:验证二叉搜索树
var isValidBST = function(root) {
    return isBST(root,Number.MIN_SAFE_INTEGER,Number.MAX_SAFE_INTEGER);
};
function isBST(root,min,max){
    if(!root){
        return true;
    }
    if(min>=root.val||max<=root.val){
        return false;
    }
    return isBST(root.left,min,root.val) && isBST(root.right,root.val,max);
}

// 700. 二叉搜索树中的搜索
var searchBST = function(root, val) {
    if(!root){
        return null;
    }
    if(val===root.val){
        return root;
    }else if(val<root.val){
        return searchBST(root.left,val);
    }else{
        return searchBST(root.right,val);
    }
};

// 第450题:删除二叉搜索树中的节点
const deleteNode = function (root, key) {
  if(root==null){
      return root;
  }
  if(root.val<key){
      root.right = deleteNode(root.right,key);
  }else if(root.val>key){
      root.left = deleteNode(root.left,key);
  }else{
      if(root.left&&!root.right){
          root = root.left;
      }else if(root.right&&!root.left){
          root = root.right;
      }else if(!root.left&&!root.right){
          root = null;
      }else{
          let last = root.left;
          while(last.right){
              last = last.right;
          }
          root.val = last.val;
          root.left = deleteNode(root.left,last.val);
      }
  }
  return root;
}

//814. 二叉树剪枝
var pruneTree = function(root) {
    return a(root);
};
function a(root){
    if(!root){
        return null;
    }
    root.left = a(root.left);
    root.right = a(root.right);
    if(!root.left&&!root.right&&!root.val){
        return null;
    }
    return root;
}

//46.给定一个 没有重复 数字的序列,返回其所有可能的全排列。
var permute = function(nums) {
    let res = [];
    let used={};
    function dfs(path){
        if(path.length===nums.length){
            res.push(path.slice())
            return;
        }
        for(let num of nums){
            if(used[num])continue;
            used[num] = true;
            path.push(num);
            dfs(path);
            path.pop();
            used[num] = false;
        }

    }
    dfs([]);
    return res;
};

//239. 滑动窗口最大值
var maxSlidingWindow = function(nums, k) {
    let queue = [];
    let result =[];
    for(let i=0;i<nums.length;i++){
        if(i-queue[0]>=k){
            queue.shift();
        }
        while(nums[queue[queue.length-1]]<=nums[i]){
            queue.pop();
        }
        queue.push(i)
        if(i>=k-1){
            result.push(nums[queue[0]])
        }
    }
    return result;
};


//无重复字符的最长子串(3)
var lengthOfLongestSubstring = function(s) {
    let arr = [];
    let max = 0;
    for(let i=0;i<s.length;i++){
        let index = arr.indexOf(s[i])
        if(index>=0){
            arr.splice(0,index+1);
        }
        arr.push(s.charAt(i));
        max = Math.max(arr.length,max);
    }
    return max;

};

1.用正则解析url

function QueryString(item) {
    var sValue = location.search.match(new RegExp("[\?\&]" + item + "=([^\&]*)(\&?)", "i"));
    return sValue ? sValue[1] : sValue;
}
//其他方法:
 let url = new URL('https://juejin.cn/editor/drafts/6940989915052113934?id=10&test=aa');
 url.searchParams.get('test');

2.图片懒加载代码

(function(){
    let images = document.querySelectorAll('img');
    let onloadImg = function(image){
        image.setAttribute('src',image.getAttribute('data-src'));
        image.addEventListener('load',()=>{
            image.removeAttribute('data-src');
        })
    }
    let IOb = new IntersectionObserver((items,observer)=>{
        console.log(items,43);
        items.forEach(item=>{
            if(item.isIntersecting){
                onloadImg(item.target);
                observer.unobserve(item.target);
            }
        })
        
    },{threshold:0.25});

    images.forEach(item=>{
        IOb.observe(item);
    })
})();

3.优先队列

function queue() {
    this.data = [];
    this.enqueue = function (item) {
        this.data.push(item);
    };
    this.dequeue = function () {
        let maxIndex = 0;
        for (let i = 0; i < this.data.length; i++) {
            if (this.data[maxIndex] < this.data[i]) {
                maxIndex = i;
            }
        }
        return this.data.splice(maxIndex, 1);
    };
}
queue();

4.找出【1000,990000】的所有对称数

function symmetry() {
    let result = [];
    for (let i = 10; i <= 988; i++) {
        let arrI = String(i).split('');
        let curI = [...arrI];
        let revI = [...arrI.reverse()];
        result.push(Number(curI.concat(revI).join('')));
    }
    return result;
}
symmetry();

5.实现函数A(),多次调用输出1,2,1,2。。。

var A = (function () {
    let i = 1;
    return () => {
        if (i % 2 === 0) {
            return i--;
        } else {
            return i++;
        }
    };
})();
A();

6.写一个发布订阅模式


class myEventEmitter {
    constructor() {
        this.list = [];
    }
    on(type, cb) {
        this.list.push({ type, cb });
    }
    emit(type, message) {
        this.list.forEach((item) => {
            if (item.type === type) {
                item.cb(message);
            }
        });
    }
}
let eventEmitter = new myEventEmitter();
eventEmitter.on('msg', (data) => console.log(data));
eventEmitter.emit('msg', 'emit');

7.给定一个数组和一个正整数N,求一个和小于N的最长连续子数组

function a(arr, num) {
    let maxLen = 0;
    let dp = Array.from(Array(arr.length), (item) => Array(arr.length).fill(0));
    for (let i = 0; i < arr.length; i++) {
        dp[i][i] = arr[i];
        for (let j = i + 1; j < arr.length; j++) {
            dp[i][j] = dp[i][j - 1] + arr[j];
            if (dp[i][j] > num) {
                break;
            } else {
                if (j - i + 1 > maxLen) {
                    maxLen = j - i + 1;
                }
            }
        }
    }
    return maxLen;
}
a([2, 345, 3, 223, 23, 5, 34, 56], 500);

8. CSS 的单行和多行截断?( overflow , text-overflow )

div{
    overflow:hidden;
    text-overflow:ellipsis;
    white-space:nowrap;
}
div{
    overflow:hidden;
    text-overflow:ellipsis;
    display:-webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
}

9.Vue 的双向绑定原理(事件监听, getter 和 setter )

var bValue = 38;
Object.defineProperty(o, 'b', {
    // 使用了方法名称缩写(ES2015 特性)
    get() {
        return bValue;
    },
    set(newValue) {
        bValue = newValue;
    },
    enumerable: true,
    configurable: true,
});

10.路径总和(112)

//给你二叉树的根节点 root 和一个表示目标和的整数 targetSum ,判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 
var hasPathSum = function(root, targetSum) {
    if(!root){
        return false;
    }
    if(root.left===null&&root.right===null){
        return (targetSum-root.val)===0
    }
    return hasPathSum(root.left,targetSum-root.val)||hasPathSum(root.right,targetSum-root.val);
};

11.二叉树的最大深度和最小深度(104)(111)


var maxDepth = function(root) {
    if(!root)return 0;
    const left = maxDepth(root.left);
    const right = maxDepth(root.right);
    return Math.max(left,right)+1;
};

var minDepth = function(root) {
    if(!root)return 0;
  
    if(!root.left){
        return Math.min(minDepth(root.right))+1;
    }
    if(!root.right){
        return Math.min(minDepth(root.left))+1;
    }
    const left = minDepth(root.left);
    const right= minDepth(root.right);
    return Math.min(left,right)+1;
};

12.Promise/A+完整实现

function Promise(executor) {
  let self = this;
  self.status = "pending";
  self.value = undefined;
  self.onResolvedCallbacks = [];
  self.onRejectedCallbacks = [];
  function resolve(value) {
    if (value instanceof Promise) {
      return value.then(resolve, reject)
    }
    setTimeout(function () { // 异步执行所有的回调函数
      if (self.status == 'pending') {
        self.value = value;
        self.status = 'resolved';
        self.onResolvedCallbacks.forEach(item => item(value));
      }
    });

  }

  function reject(value) {
    setTimeout(function () {
      if (self.status == 'pending') {
        self.value = value;
        self.status = 'rejected';
        self.onRejectedCallbacks.forEach(item => item(value));
      }
    });
  }

  try {
    executor(resolve, reject);
  } catch (e) {
    reject(e);
  }
}
function resolvePromise(promise2, x, resolve, reject) {
  if (promise2 === x) {
    return reject(new TypeError('循环引用'));
  }
  let then, called;

  if (x != null && ((typeof x == 'object' || typeof x == 'function'))) {
    try {
      then = x.then;
      if (typeof then == 'function') {
        then.call(x, function (y) {
          if (called)return;
          called = true;
          resolvePromise(promise2, y, resolve, reject);
        }, function (r) {
          if (called)return;
          called = true;
          reject(r);
        });
      } else {
        resolve(x);
      }
    } catch (e) {
      if (called)return;
      called = true;
      reject(e);
    }
  } else {
    resolve(x);
  }
}
Promise.prototype.then = function (onFulfilled, onRejected) {
  let self = this;
  onFulfilled = typeof onFulfilled == 'function' ? onFulfilled : function (value) {
    return value
  };
  onRejected = typeof onRejected == 'function' ? onRejected : function (value) {
    throw value
  };
  let promise2;
  if (self.status == 'resolved') {
    promise2 = new Promise(function (resolve, reject) {
      setTimeout(function () {
        try {
          let x = onFulfilled(self.value);
          resolvePromise(promise2, x, resolve, reject);
        } catch (e) {
          reject(e);
        }
      });

    });
  }
  if (self.status == 'rejected') {
    promise2 = new Promise(function (resolve, reject) {
      setTimeout(function () {
        try {
          let x = onRejected(self.value);
          resolvePromise(promise2, x, resolve, reject);
        } catch (e) {
          reject(e);
        }
      });
    });
  }
  if (self.status == 'pending') {
    promise2 = new Promise(function (resolve, reject) {
      self.onResolvedCallbacks.push(function (value) {
        try {
          let x = onFulfilled(value);
          resolvePromise(promise2, x, resolve, reject);
        } catch (e) {
          reject(e);
        }
      });
      self.onRejectedCallbacks.push(function (value) {
        try {
          let x = onRejected(value);
          resolvePromise(promise2, x, resolve, reject);
        } catch (e) {
          reject(e);
        }
      });
    });
  }
  return promise2;
}
Promise.prototype.catch = function (onRejected) {
  return this.then(null, onRejected);
}
Promise.all = function (promises) {
  return new Promise(function (resolve, reject) {
    let result = [];
    let count = 0;
    for (let i = 0; i < promises.length; i++) {
      promises[i].then(function (data) {
        result[i] = data;
        if (++count == promises.length) {
          resolve(result);
        }
      }, function (err) {
        reject(err);
      });
    }
  });
}

Promise.race = function (promiseAry) {
    return new Promise((resolve, reject) => {
        for (let i = 0; i < promiseAry.length; i++) {
            promiseAry[i].then(resolve, reject);
        }
    });
};

Promise.deferred = Promise.defer = function () {
  var defer = {};
  defer.promise = new Promise(function (resolve, reject) {
    defer.resolve = resolve;
    defer.reject = reject;
  })
  return defer;
}
/**
 * npm i -g promises-aplus-tests
 * promises-aplus-tests Promise.js
 */
try {
  module.exports = Promise
} catch (e) {
}

13.实现一个带有并发限制的pormise调度器

// 实现有并行限制的Promise调度器
// JS实现一个带并发限制的异步调度器Scheduler,保证同时运行的任务最多有两个。完善下面代码的Scheduler类,使以下程序能够正常输出:

class Scheduler {
    constructor() {
        this.queue = [];
        this.curIndex = 0;
        this.maxIndex = 2;
    }
    add(promiseCreator) {
        this.queue.push(promiseCreator);
    }
    request(i) {
        if (!this.queue || !this.queue.length || this.runCounts >= this.maxCount) {
            return;
        }
        this.curIndex++;
        this.queue
            .shift()()
            .then(() => {
                this.curIndex--;
                this.request();
            });
    }
    start() {
        for (let i = 0; i < this.maxIndex; i++) {
            this.request(i);
        }
    }
}

const timeout = (time) =>
    new Promise((resolve) => {
        setTimeout(resolve, time);
    });

const scheduler = new Scheduler();

const addTask = (time, order) => {
    scheduler.add(() => timeout(time).then(() => console.log(order)));
};

addTask(1000, '1');
addTask(500, '2');
addTask(300, '3');
addTask(400, '4');
scheduler.start();
// output: 2 3 1 4