手写 Promise之ajax、all、race|小册免费学

472 阅读2分钟

定义

Promise的MDN定义:

Promise 对象用于表示一个异步操作的最终完成 (或失败)及其结果值。

ECMAscript 6 原生提供了 Promise 对象。 Promise的构造函数接收一个实参,是函数,并且传入两个参数:resolvereject,分别表示异步操作执行成功后的回调函数和异步操作执行失败后的回调函数。其实这里用成功和失败来描述并不准确,按照标准来讲,resolve是将Promise的状态置为fullfiledreject是将Promise的状态置为rejected

Promise 支持链式调用,解决了回调地狱,then可以接收两个函数(resolvereject),catch方法的优势是不仅可以捕获Promise的变为reject状态的异常,还可以捕获then中的代码异常。

resolverejectPromise的方法,thencatchPromise实例的方法。

Promise 对象很好的解决了以前ajax实现网络请求的回调地狱问题,同时还提供了其他丰富的用法。我们自己尝试实现一下这些方法,加强对Promise的理解。

Promise实现ajax

/* 
  Promise实现ajax
*/
function ajax(URL) {
  return new Promise((resolve, reject) => {
    let req = new XMLHttpRequest();
    req.open('get', URL, true);
    req.onload = () => {
      if (req.status === 200) {
        resolve(req.responseText);
      } else {
        reject(new Error(req.statusText));
      }
    };
    req.onerror = () => {
      reject(new Error(req.statusText));
    };
    req.send();
  });
}

Promise.all

Promise.all可以将多个Promise实例包装成一个新的Promise实例。同时,成功和失败的返回值是不同的,成功的时候返回的是一个结果数组,而失败的时候则返回最先被reject失败状态的值。all里面全部都成功all才是成功,任一个失败all就会失败,不管其他的是成功还是失败。

需要特别注意的是,Promise.all([p1,p2,p3])获得的成功结果的数组里面的数据顺序和Promise.all接收到的数组顺序是一致的,即p1的结果在前,即便p1的结果获取的比p2晚。这带来一个绝大的好处:在前端开发请求数据的过程中,偶尔会遇到发送多个请求并根据请求顺序获取和使用数据的场景,使用Promise.all就可以解决这个问题。

Promise.prototype.all = function(promises) {
  let results = [];
  let promisesCount = 0;
  let promisesLength = promises.length;
  return new Promise(function(resolve, reject) {
    for (let i = 0; i < promises.length; i++) {
      const element = promises[i];
      Promise.resolve(element).then(function(res) {
        promisesCount ++;
        results[i] = res;
        if (promisesCount === promisesLength) {
          resolve(results);
        }
      }, function(err) {
        reject(err);
      });
    }
  });
};

Promise.race

Promise.race就是赛跑的意思,意思就是说Promise.race([p1,p2,p3])里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。

Promise.prototype.race = function(promises) {
  let hasValue = false;
  let hasError = false;
  return new Promise(function(resolve, reject) {
    for (let i = 0; i < promises.length; i++) {
      const element = promises[i];
      Promise.resolve(element).then(function(res) {
        if (!hasValue && !hasError) {
          resolve(res);
          hasValue = true;
        }
      }, function(error) {
        if (!hasValue && !hasError) {
          reject(error);
          hasError = true;
        }
      })
    }
  })
}

本文正在参与「掘金小册免费学啦!」活动, 点击查看活动详情