Promise面试的常见手写题目

544 阅读2分钟

图片最多同时加载X张的处理方案

var urls = [
    'https://www.999code.com/path/1.jpg',
    'https://www.999code.com/path/2.jpg',
    'https://www.999code.com/path/3.jpg',
    'https://www.999code.com/path/4.jpg',
    'https://www.999code.com/path/5.jpg',
    'https://www.999code.com/path/6.jpg',
    'https://www.999code.com/path/7.jpg',
    'https://www.999code.com/path/8.jpg',
    'https://www.999code.com/path/9.jpg',
    'https://www.999code.com/path/10.jpg',
  ];


function loadImg(url) {
    return new Promise((resolve, reject) => {
      const img = new Image();
      img.onload = function() {
        console.log("一张图片加载完成");
        resolve(img);
      };
      img.onerror = function() {
          reject(new Error('Could not load image at' + url));
      };
      img.src = url;
    });
    
    
function limitLoad(urls, handler, limit) {
    let sequence = [].concat(urls); // 复制urls
    // 这一步是为了初始化 promises 这个"容器"
    let promises = sequence.splice(0, limit).map((url, index) => {
        return handler(url).then(() => {
            // 返回下标是为了知道数组中是哪一项最先完成
            return index;
        });
    });
    // 注意这里要将整个变量过程返回,这样得到的就是一个Promise,可以在外面链式调用
    return sequence
        .reduce((pCollect, url) => {
            return pCollect
                .then(() => {
                    return Promise.race(promises); // 返回已经完成的下标
                })
                .then(fastestIndex => { // 获取到已经完成的下标
                    // 将"容器"内已经完成的那一项替换
                    promises[fastestIndex] = handler(url).then(
                        () => {
                            return fastestIndex; // 要继续将这个下标返回,以便下一次变量  返回值并没有什么其他的价值但是handler处理过程有意义
                        }
                    );
                })
                .catch(err => {
                    console.error(err);
                });
        }, Promise.resolve()) // 初始化传入
        .then(() => { // 最后三个用.all来调用
            return Promise.all(promises);
        });
}



limitLoad(urls, loadImg, 3)
    .then(res => {
        console.log("图片全部加载完毕");
        console.log(res);
    })
    .catch(err => {
        console.error(err);
    });

使用Promise实现红绿灯交替重复亮

红灯3秒亮一次,黄灯2秒亮一次,绿灯1秒亮一次;如何让三个灯不断交替重复亮灯?

要求:用Promise实现

三个亮灯函数已经存在:

const d = new Date() * 1
function red() {
  console.log(new Date() * 1 - d)
  console.log("red");
}
function green() {
  console.log(new Date() * 1 - d)
  console.log("green");
}
function yellow() {
  console.log(new Date() * 1 - d)
  console.log("yellow");
}

function light(timer, cb) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      cb()
      resolve()
    }, timer)
  })
}

function step() {
  Promise.resolve().then(() => {
    return light(3000, red)
  }).then(() => {
    return light(2000, green)
  }).then(() => {
    return light(1000, yellow)
  }).then(() => {
    step()
  })
}
step()
// light(3000,red)

实现mergePromise函数

把传进去的数组按顺序先后执行,并且把返回的数据先后放到数组data中。


const time = (timer) => {
    return new Promise(resolve => {
      setTimeout(() => {
        resolve()
      }, timer)
    })
  }
  const ajax1 = () => time(2000).then(() => {
    console.log(1);
    return 1
  })
  const ajax2 = () => time(1000).then(() => {
    console.log(2);
    return 2
  })
  const ajax3 = () => time(1000).then(() => {
    console.log(3);
    return 3
  })
  
  mergePromise([ajax1, ajax2, ajax3]).then(data => {
    console.log("done");
    console.log(data); // data 为 [1, 2, 3]
  });
  
  // 要求分别输出
  // 1
  // 2
  // 3
  // done
  // [1, 2, 3]

  function mergePromise(ajaxArray){
    const data=[]
    let promise=Promise.resolve()
    ajaxArray.forEach(ajax => {
        promise=promise.then(ajax).then(res=>{
            data.push(res)
            return data
        })
    });
    return promise
  }