Promise

103 阅读4分钟

为什么需要Promise对象

我们之前获取异步操作后的结果是通过什么方式获取的?是回调函数。比如下面的一个实例

 d3.csv("cities.csv", function(data) {console.log(data)});
 //这是d3中读取文件的函数,第二个参数就是回调函数。用它拿到读取结果。

如果我们有很多的读取操作而且后面的读取操作需要依赖之前读取的结果。比如下面

 d3.csv("cities.csv", function(data) {
    d3.csv(data[0].url,function(data2){
        ......//更多操作
  })
 });

如果就这样嵌套很多层,不仅写着难受,后面再来维护修改时,看代码更难受。Promise的出现就可以解决这个问题。

Promise基本理解和用法

我的理解是,promise就像我们平时委托的第三方一样,我们把异步操作交给它,让第三方(promise)自己处理执行,不受外界影响。处理好之后我们就可以用then方法取出。

promise有三种状态,分别是:pending、fulfilled、rejected; 当 promise执行resolve是状态由pending->fulfilled; 当 promise执行reject是状态由pending->rejected; 状态一旦改变就不会再变。这说起来很抽象直接看一下例子。

基本用法
  const promise = new Promise(function(resolve, reject) {
  // ... some code

  if (/* 异步操作成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});

Promise对象是一个构造函数,实例后的Promise是一个对象,该构造函数接受一个函数参数,这个函数参数传入两个参数(resolve,reject), 这两个参数是各是一个函数方法; 我们可以根据函数的结果来判断执行resolve或reject;

then()的用法
promise.then(()=>{ /* resolve 的执行内容 */ },()=>{ /*reject执行的内容*/ } )

.then()方法接受两个函数参数,第一个参数是获取resolve的内容来执行异步操作,第二个参数是执行reject,然后执行一个捕获错误的内容,貌似可以获取代码执行错误的位置; 、第一个函数接受一个来自promise的构造函数resolve传递的对象; 3.2、第二个函数会不会promise构造函数的错误;

注意:建议是不推荐 .then(()=>{},()=>{/捕获错误/}) 这样去捕获错误,而是推荐用.catch的方法去捕获错误 .then(()=>{/resolve 内容/}).catch(error){/error捕获错误/}。因为直接在后面点catch()就能够捕获第一次发生错误的地方。

解决前面的问题

运用promise做多层次的回调 终取到这个节点,但是如果用promise就能够同步异步操作去获取到;

   console.log('start');
  var promise1 = new Promise((resolve,reject)=>{
              setTimeout(resolve('葡萄'),1);
          });
  promise1.then(value=>new Promise((resolve,reject)=>setTimeout(resolve(value+',苹果'),1)))
          .then(value=>new Promise((resolve,reject)=>setTimeout(resolve(value+',橘子'),1)))
          .then(value=>new Promise((resolve,reject)=>setTimeout(resolve(value+',香蕉'),1)))
          .then(value=>new Promise((resolve,reject)=>setTimeout(resolve(value+',西瓜'),1)))
          .then(value=>{console.log(value)});

  console.log('上面是个异步过程,所以我先出来,后面才是水果');
  
  /*
    控制台打印:
    start
    上面是个异步过程,所以我先出来,后面才是水果
    葡萄,苹果,橘子,香蕉,西瓜
  */                                                                                                                                                                                                                                                                                           

这里的then都只执行了成功(resolve)方法,来把前面的只拼接起来传给下个then()方法去接受,下个then的value接受到上面的值继续new Promise 来执行下一个异步操作;

all方法

Promise.all() 接收一个 promise对象的数组作为参数,当这个数组里的所有promise对象全部变为resolve或reject状态的时候,它才会去调用 .then() 方法。

// `delay`毫秒后执行resolve
  function timerPromisefy(delay) {
      return new Promise(function (resolve) {
         setTimeout(function () {
             resolve(delay);
         }, delay);
     });
  }
  var startDate = Date.now();
  // 所有promise变为resolve后程序退出
  Promise.all([
      timerPromisefy(1),
      timerPromisefy(32),
      timerPromisefy(64),
      timerPromisefy(128)
  ]).then(function (values) {
     console.log(Date.now() - startDate + 'ms');
      // 約128ms
     console.log(values);    // [1,32,64,128]
  });

所以,promise.all,会在所有的参数里的Promise方法执行完再返回所有数据,以数组的格式。

race()方法

Promise.race()的参数跟all一样是接受一个promise对象数组,不同的是race(),的结果是只要有一个promise变个fulfilled或rejected就能够then()中获取值,然后其他的Promise对象则会继续执行。

  // `delay`毫秒后执行resolve
 function timerPromisefy(delay) {
    return new Promise(function (resolve) {
         setTimeout(function () {
           console.log(delay)
             resolve(delay);
         }, delay);
    });
 }
 // 任何一个promise变为resolve或reject 的话程序就停止运行
 Promise.race([
    timerPromisefy(1),
    timerPromisefy(32),
     timerPromisefy(64),
     timerPromisefy(128)
 ]).then(function (value) {
    console.log('then',value);    // => 1
 });
 
 控制台
 /*
 1 
 32
 64
 128
 then,1 
 */

本文部分 实例 来自链接:juejin.cn/post/684490… 。 这篇文章写得很好,推荐阅读