promise常用知识点小结

483 阅读5分钟

一、promise简介


promise是异步编程的一种解决办法:语法上来看promise是对象,从它可以获得一部操作的信息;从本意上来讲,它是约定,约定过一段时间给你一个结果。

promise有三种状态:

  • pending => 等待态
  • fulfiled => 成功态
  • rejected => 失败态

回调函数的产生,就是将一个函数作为一个数据传值给另外一个函数,另外的函数调用这个传递过来的函数并调用,那么这个函数就成功成为回调函数了!

//当参数num满足一定的条件就执行传入的函数,这个函数就是回调函数
function fn1(a,fn){
  if(a > 15 && typeof fn == 'function'){
    fn(); //执行fn
  }
}
fn1(16,function(){
  console.log('this is a callback');
})

一般情况下,回调嵌套最多一到两层,当我们遇到回调嵌套很多的时候。代码就显得非常的复杂,会给编程带来麻烦,这样情形就叫做回调地狱

promise的诞生就自带光环,来解决了:

  • 回调地狱
  • 可以解决异步相关的问题
  • 支持多个并发的请求

二、promise使用


promise是一个构造函数,自己身上有call、reject、resolve等方法,原型上面有then、catch等方法。

let p = new Promise((resolve,reject) => {
  //下面是异步操作的方法
  setTimeout(() => {
    console.log('执行完成');
    resolve('成功啦');
  },2000)
});

Promise构造函数接收一个参数:function,并且这个函数需要传入两个参数:

  • resolve:异步操作执行成功后的回调函数
  • reject:异步操作执行失败后的回调函数

then链式操作的用法

实质上promise的最称赞的地方是状态,以维护状态传递状态的方式来使得回调函数能够及时的调用,比传递callback function要简单、灵活,所以应该这样使用promise:

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

reject的用法

将promise的状态设置为rejected,这样我们在then中就能捕捉到,然后去执行失败的回调。

let p = new Promise((resolve,reject) => {
  //异步操作
  setTimeout(() => {
    let number = Math.ceil(Math.random() * 10); //生成1--10的随机数,ceil()传回大于等于所给数字的整数
    if(number <= 5){
      resolve(num);
    }else{
      reject('这个数字太大了!');
    }
  },2000);
});
p.then((data) => {
  console.log('resolve',data);
},(err){
  console.log('reject',err);
})

then中传了两个参数,then方法可以接受两个参数,第一个参数就是resolve的回调,第二个参数就是reject的回调。

catch的使用

我们知道promise对象除了then方法外,还有一个catch方法,它其实就是then的第二个参数的作用,专门用来指定reject回调的。

p.then((data) => {
  console.log('resolve',data);
}).catch((err) => {
  console.log('reject',err);
})

它的效果和then中的第二个参数的效果是一样的;再执行resolve的回调的时候,如果抛出了异常,并不会报错卡死js代码,而是会到catch方法中。

p.then((data) => {
  console.log('resolve',data);
  console.log(hhz); //并没有hhz变量
}).catch((err) => {
  console.log('reject',err);
})

在上面的案例中,then中的最后一个输出,hhz这个变量并没有定义,如果不是promise,这里就会报错,并程序停止执行,但是promise会继续执行,进入到catch中去,并会爆出错误。

all的用法

promise的all方法提供了并行执行异步操作的能力,并且所有的异步操作执行完成后才执行回调。

let p1 = new Promise( (resolve,reject) =>{
  //异步操作
})
let p2 = new Promise( (resolve,reject) =>{
  //异步操作
})
let p3 = new Promise( (resolve,reject) =>{
  //异步操作
})
let p = new Promise.all([p1,p2,p3])
p.then(() => {
  //三个成功,就成功
},() => {
  //失败,都算失败
})

有了 all 方法之后,就可以并行执行多个异步操作,并在一个回调中处理所有的返回数据。

race的用法

race的使用场景是:给某个异步操作设置超时时间,并且在超时后执行相应的操作,代码如下:

//请求视频资源
function requestVideo(){
  let p = new Promise( (resolve,reject) => {
    let video = new Video();
    video.onload = function(){
      resolve(video);
    }
    video.src = 'video的路径';
  } );
  return p;
}

//延时函数,用于给请求计时
    function timeout(){
        var p = new Promise((resolve, reject) => {
            setTimeout(() => {
                reject('图片请求超时');
            }, 5000);
        });
        return p;
    }
    Promise.race([requestImg(), timeout()]).then((data) =>{
        console.log(data);
    }).catch((err) => {
        console.log(err);
    });

requestImg函数会异步请求一张图片,我把地址写为"图片的路径",所以肯定是无法成功请求到的。timeout函数是一个延时5秒的异步操作。我们把这两个返回Promise对象的函数放进race,于是他俩就会赛跑,如果5秒之内图片请求成功了,那么遍进入then方法,执行正常的流程。如果5秒钟图片还未成功返回,那么timeout就跑赢了,则进入catch,报出“图片请求超时”的信息。

三、实现自己的promise

1.实现成功和失败的回调

要实现上面代码中的功能,也是promise最基本的功能。首先,需要创建一个构造函数promise,创建一个promisel类,在使用的时候传入了一个执行器executor,executor会传入两个参数:成功(resolve)和失败(reject)。之前说过,只要成功,就不会失败,只要失败就不会成功。所以,默认状态下,在调用成功时,就返回成功态,调用失败时,返回失败态。代码如下:

class Promise {
  constructor(executor){
    //默认状态是等待
    this.status = 'pedding';
    this.value = undefined;
    this.reason = undefined;
    //存放成功的回调
    this.onResolveCallbacks = [];
    //存放失败的回调
    this.onRejectCallbacks = [];
    let resolve = (data) => {
      //this指向的是实例
      if(this.status === 'pedding'){
        this.value = data;
        this.status = 'resolved';
        this.onResolveCallback.forEach(fn => fn());
      }
    }
    let reject = (reason) => {
            if(this.status === 'pending'){
                this.reason = reason;
                this.status = 'rejected';
                this.onRejectedCallbacks.forEach(fn => fn());
            }
        }
        try{//执行时可能会发生异常
            executor(resolve,reject);
        }catch (e){
            reject(e);//promise失败了
        }
  }
}

文章说明:

文章很多学习借鉴了下面这个金主,文章总结的很优秀,所以想保存在自己这边方便查询和回忆。我这个是不全的,想看全内容和更精彩的内容,请访问下面的这位金主。

作者:蔓蔓雒轩

链接:juejin.cn/post/684490…

来源:掘金

著作权归作者蔓蔓雒轩所有。商业转载请联系作者获得授权,非商业转载请注明出处。