ES6 Promise

142 阅读5分钟

什么是Promise

Promise 是异步编程的一种解决方案,比传统的异步解决方案【回调函数】和【事件】更合理、更强大。现已被 ES6 纳入进规范中。也可说Promise对象用于表示一个异步操作的最终状态(成功或失败)以及其返回的值。 (同步与异步:同步任务会阻塞程序执行,异步不会)

Promise 的三种状态

  1. 对象的状态不受外界影响,Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败),只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态,这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。
  2. 一旦状态改变,就不会再变,任何时候都可以得到这个结果,Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected,只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型),如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果,这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。
  3. Promise对象优点,可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数

Promise 的常用 API

Promise.all()

  1. Promise.all方法可以把多个promise实例,包装成一个新的promise实例。
  2. Promise.all([ promise1, promise2 ]) : Promise。all()方法接收一个数组(两个Promise实例)作为参数,最终返回一个Promise实例。
  3. 决议的3中情况:promise1, promise2都决议成功,则Promise.all决议成功,1和2实例返回的参数以数组的形式按顺序传递出去;如果1和2中有一个失败,则最终决议为失败,并将失败的结果传递出去;如果没有1和2,all参数为空,则最终决议成功。
  4. 例:模拟需要多个请求的数据 才能进行下一步操作的情况
function getData1() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log('第一条数据加载成功');
      resolve('data1');
    }, 1000);
  });
}

function getData2() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log('第二条数据加载成功');
      resolve('data2');
    }, 1000);
  });
}

function getData3() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log('第三条数据加载成功');
      resolve('data3');
    }, 1000);
  });
}

function getData4() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log('第四条数据加载成功');
      resolve('data4');
    }, 2000);
  });
}
let p = Promise.all([getData1(), getData2(), getData3(), getData4()]);
p.then(arr => {
  console.log(arr);
}, e => {
  console.log(e);
});

将getData4做如下改动。其中有一个实例是失败,则最终决议会失败,返回失败后的数据

function getData4() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      // console.log('第四条数据加载成功');
      reject('data4 err');
    }, 500);
  });
}

如果不传参数,最终决议成功

let p = Promise.all([]);
p.then(() => {
  console.log('aaa');
}, e => {
  console.log(e);
});

如果不使用Promise.all来写

let count = 0;
let err = false;

function func() {
  if (count < 4) return;
  if (err) {
    // ....
  }
  console.log('全部拿到了 !');
}
![](https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2019/11/12/16e5e6c5cf502c65~tplv-t2oaga2asx-image.image)

function getData1() {
  setTimeout(() => {
    console.log('第一条数据加载成功');
    count ++;
    func();
  }, 1000);
}

function getData2() {
  setTimeout(() => {
    console.log('第二条数据加载成功');
    count ++;
    func();
  }, 1000);
}

function getData3() {
  setTimeout(() => {
    console.log('第三条数据加载成功');
    count ++;
    func();
  }, 1000);
}

function getData4() {
  setTimeout(() => {
    console.log('第四条数据加载成功');
    count ++;
    func();
  }, 1000);
}

getData1();
getData2();
getData3();
getData4();

Promise.race()

  1. 与Promise.all() 相反,其中有1个参数是失败的,则最终决议失败,并立即将失败的结果返回。如果参数为空,将会一直被挂起。 Promise.race([ promise1, promise2 ]) : Promise
  2. Promise.race([p1, p2, p3])里面哪个结果获得的快,就返回哪个结果,不管结果本身是成功状态还是失败状态
function getData1() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log('第一条数据加载成功');
      reject('err');
    }, 500);
  });
}

function getData2() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log('第二条数据加载成功');
      resolve('data2');
    }, 1000);
  });
}

function getData3() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log('第三条数据加载成功');
      resolve('data3');
    }, 1000);
  });
}
let p = Promise.all([getData1(), getData2(), getData3()]);
// let p = Promise.race([]);

p.then(data => {
	console.log(data);
}, e => {
	console.log(e);
})

不使用Promise.race()

let flag = false;
function func(data) {
  if (flag) return;
  flag = true;

  console.log(data);
}

function getData1() {
  setTimeout(() => {
    console.log('第一条数据加载成功');
    func({name: 'xiaoming'});
  }, 500);
}

function getData2() {
  setTimeout(() => {
    console.log('第二条数据加载成功');
    func({name: 'xiaohong'});
  }, 600);
}

getData1();
getData2();

Promise.resolve(value) 和 Promise.reject(value)

常用来生成已经被决议为失败或者成功的promise实例。可以传递一个普通的值,或者传递一个promise实例。

  1. 传递一个普通的值
let p1 = new Promise(resolve => {
  resolve('成功!');
});
// p2等同于p1
let p2 = Promise.resolve('成功!');

2.传递一个promise实例; value 本身就是 Promise 对象,则该对象作为 Promise.resolve 方法的返回值返回

let poruomiesi = new Promise(resolve => {
  resolve('耶!')
});

// 直接返回传递进去的promise
let p = Promise.resolve(poruomiesi);

p.then(data => void console.log(data));

console.log(p === poruomiesi); 

3. 传递一个thenable,then会被立即执行

 let p = {
  then(cb) {
    console.log('我被执行了');
    cb('222');
  },
  oth() {
    console.log('我不会执行');
  }
};

let m = Promise.resolve(p).then(data => {
  console.log(data);
  // 我被执行了 
  // 222
});

Promise.reject()

Promise.reject({ then() { console.log(1) } })
  .then(() => {
    console.log('我不会被执行');
  }, e => {
    console.log(e); // 直接将上面传入的对象输出,不做任何处理
  });

console.log(1);

let p = new Promise(resolve => {
  console.log(2);
  resolve();
  console.log(3);
});

console.log(4);

p.then(() => {
  console.log(5);
});

console.log(6);

将同步的任务转成异步任务

function createAsyncTask(syncTask) {
  return Promise.resolve(syncTask).then(syncTask => syncTask());
}

createAsyncTask(() => {
  console.log('我变成了异步任务!!!');
  return 1 + 1;
}).then(res => {
  console.log(res);
});

console.log('我是同步任务!');