前端Promise最全笔记

目录

  • 什么是Promise?
  • Promise对象的特点
  • Promise 与 resolve() 的使用方法
  • reject() 的用法
  • catch()的用法
  • Promise.all()的用法
  • Promise.race()的用法
  • Promise.any()的用法
  • 面试题:Promise 代码执行顺序
  • 面试题:Promise的状态
  • finally()方法(使用较少)
  • 面试题:async 和 await 相关
  • 面试题:Promise中抛出错误
  • 面试题: 综合题目

前言

  • JS是单线程的,想要提高JS的能力,异步相关的解决方法和原理都是非常值得学习的
  • 这一份Promise笔记是我自己看了大量其他作者的笔记进行整理的,可能也有理解不透彻的地方,若有问题欢迎留言指正,谢谢!
  • 本文旨在详细解读Promise的基本使用和方法,不涉及原理层面的探讨,所以如有啰嗦的地方还请见谅,希望可以帮助到小白成长~
  • 如果你静下心来认真看一遍,相信会有一定的帮助

什么是Promise?

Promise是异步编程的一种解决方案,其实是一个构造函数,本身有 all、any、race、reject、resolve方法,原型上有 then、catch方法

Promise对象的特点

1. 对象的状态不受外界影响
一共有3种状态 ① pending进行中;② fulfilled已成功;③rejected已失败
只有异步操作的结果可以决定当前是哪一种状态,其他的任何操作都不会改变promise的状态

2. 状态一旦确定就不会再改变,且任何时候都可以得到这个状态结果
Promise对象的状态改变有两种可能:
① 从pending转变为fulfilled;② 从pending转变为rejected。
只要这两种情况发生了,那么promise就会一直保持这个状态的结果,称为状态定型

Promise 与 resolve() 的使用方法

通过new关键字创建一个Promsie对象以后,promise对象会自动执行内部回调函数,看下列代码:

	let p = new Promise(function(resolve, reject) {
    	setTimeout(function() {
      	  console.log('执行完成Promise');
       	 resolve('返回resolved状态');
    }, 2000);
	// 2s后会执行输出语句输出  执行完成Promise

上述代码中,不仅执行回调函数中的输出语句,同时也通过resolve()方法返回了promise对象的状态(或者说将对象的状态修改为成功),意思就是当前的promise的对象已经从pending状态变为resolved状态,且状态不会再发生改变

针对上述创建Promise对象就会自动执行回调函数的情况,我们在实际使用过程当中一般是将构造Promise对象的过程封装在一个箭头函数中,然后return返回promise对象

// 使用匿名函数 promiseClick() 封装
const promiseClick = () => {
    console.log('点击方法被调用')
    let p = new Promise(function(resolve, reject) {
        //做一些异步操作
        setTimeout(function() {
            console.log('执行完成Promise');
            resolve('promise状态变为resolved');
        }, 2000);
    });
    return p
}

调用promiseClick()函数的时候,首先执行的是console.log输出语句,然后构造一个promise对象,最后return返回该对象。因此,我们调用该函数的时候,就可以紧跟着使用promise身上的 .then()方法

promiseClick().then(function(data) {
    console.log(data)   //输出是:promise状态变为resolved
})

.then() 方法中可以通过逗号分隔,定义两个回调函数,第一个回调函数是处理resolved状态,第二个是处理rejected转态。对于上述代码来说,调用promiseClick()后返回的promise对象的状态是 resolved,因此.then()中的回调函数接收的data参数值就是resolve()中返回的状态值,即【promise状态变为resolved】

.the()方法的作用就是重新调用函数,所以在有多层回调的时候,就在上一级.then()方法中返回一个Promsie对象,然后就可以继续使用 .then()方法进行回调,从而解决了回调地狱的问题

reject() 的用法

上述提到的Promise与resolve的使用,简单来说就是Promise对象成功回调的时候,resolve将Promise对象的状态修改为fulfilled,那么Promise对象调用失败的时候呢?

reject()就是将Promise对象的状态修改为rejected(已失败),请注意它只是修改promise对象的状态

刚才提到的then()方法中可以定义两个回调函数,如果只定义了一个就是只处理resolved的情况,所以定义第二个的时候就可以用来处理rejected的情况

function promiseClick() {
    let p = new Promise(function(resolve, reject) {
        setTimeout(function() {
            var num = Math.ceil(Math.random() * 20); //生成1-10的随机数
            console.log('随机数生成的值:', num)
            if (num <= 10) {
                resolve(num);
            } else {
                reject('数字大于10了即将执行失败回调');
            }
        }, 2000);
    })
    return p
}

promiseClick().then(
    function(data) {
        console.log('resolved回调成功');
        console.log('resolved状态值:', data);
    },
    function(reason) {
        console.log('rejected回调失败');
        console.log('rejected状态的原因:', reason);
    }
);

catch() 的用法

catch()是与then()并行的一个方法,作用是捕获异常,具体来说是: ① 可以代替then()方法中的第二个回调函数,用来捕获rejcted状态;② 第二个作用比较重要,如果resolved状态下的回调函数在执行过程中抛出了异常,当紧跟then()方法使用catch()方法以后,catch中就可以解决这个异常,从而不会导致阻塞js的运行,异常的原因也会传到catch中

作用一:

promiseClick().then(
        function(data) {
            console.log('resolved回调成功');
            console.log('resolved状态值:', data);
        }
    )
    .catch(function(reason, data) {
        console.log('rejected状态:', data);
    });

作用二:

promiseClick().then(
        function(data) {
            console.log('resolved回调成功');
            console.log('resolved状态值:', data);
        }
    )
    .catch(function(reason, data) {
        console.log('异常原因:', reason);
    });

Promise.all()的用法

all()是与the()同级的一个方法,该方法的特点是:提供了并行执行异步操作的能力,并且在所有的异步操作执行完成且所有异步操作的状态是resolved状态才会执行回调函数

下列代码,数组中全部都是封装好的构造promise对象的函数名(上面提到过),执行这些函数以后,均会返回一个promise对象且带有resolved或rejected状态

Promise
    .all([promiseClick3(), promiseClick2(), promiseClick1()])
    .then(function(results) {
        console.log(results);
    });

只有当数组中的所有函数执行完,且全部返回带有resolve状态的promise对象后,才会紧跟着去执行then()方法中的回调函数

then()方法接收的results指的就是上述数组中返回的状态结果值,这个状态结果值也是以数组的形式传递到then()方法中,从而在then()的回调函数中就可以处理所有的返回的数据

举个例子:promiseClick3(), promiseClick2(), promiseClick1()返回的resolved状态值分别是:1,5, 3,那么results接收的值就是数组 [1, 5, 3]

Promise.race()的用法

race()与all()方法相似但又有不同之处,通过race的中文含义就可以感受到。race()方法是:数组中调用的函数,谁先返回Promise对象并带有状态值(可以是resolved也可以是rejectd),那么就先执行谁,其他的promise对象的异步操作就不会再进入到race()中,这一点需要注意一下,并不是按照先后顺序执行,只会执行第一个进来的promise对象处理并处理对应的状态值

 Promise
     .race([promiseClick3(), promiseClick2(), promiseClick1()])
     .then(function(results) {
         console.log('成功', results);
     }, function(reason) {
         console.log('失败', reason);
     });

使用race()的时候,后面的then()方法中一般定义两个回调函数,因为最先进来的promise对象的状态值可能是resolved也可能是rejected。如果then()中只定义了一个回调函数,也可以通过在then()的后面定义一个catch()方法,catch也是可以接捕获rejected状态的

Promise.any()的用法

只要any()的数组中有一个Promise对象是resolved,就会执行回调输出结果

Promise.race() 返回的是第一个结果(有可能是resolve/reject),但是any返回的一定是第一个成功的结果(resolve),any会忽略掉出现resolve之前所有的reject

面试题:Promise 代码执行顺序

  1. 涉及代码执行顺序时候,就需要考虑是:同步任务还是异步任务,异步任务又需要细分为微任务与宏任务。我不深入讲区别,简单来说一下执行顺序的原则

  2. 代码从上往下执行的时候,遇到同步任务立即执行,遇到微任务就暂时放入微任务队列中暂不执行,遇到宏任务就暂时放入宏任务队列暂不执行。同步任务全部执行完毕,才从微任务队列中取出微任务依次执行。微任务全部执行完毕,才从宏任务队列中取出宏任务依次执行

  3. 同步任务代码中可能会包括同步任务、微任务、宏任务,微任务和宏任务也都有这种可能,但是无论如何,严格按照第2条说到的原则执行

任务类型任务
微任务Promise、async/await
宏任务定时器、ajax、DOM操作
new Promise((resolve, reject) => {
  console.log('new Promise')
  resolve('success')
})
console.log('finished')

// 输出结果顺序:
new promise   
finished
  1. resolve()只是确定了当前promise的转态,不会产生输出的操作

  2. 考察new创建Promise对象就会立即执行回调函数,new的过程是同步的

Promise.resolve(1)
    .then(res => {
        console.log(res)     // => 1
        return 2             // 包装成 Promise.resolve(2)
    })
    .then(res => {
        console.log(res)     // => 2
    })
    
    // 输出结果是:
    1   
    2
  1. Promise.resolve()表示promise对象的状态已经确定,是resolved状态,所以就可以执行then()中的回调函数

  2. 需要注意的是:Promise.resolve()是微任务,是次于同步任务执行的。但是这一段代码中没有同步任务,所以就直接执行微任务

const promise = new Promise((resolve, reject) => {
    console.log(1);
    console.log(2);
});
promise.then(() => {
    console.log(3);
});
console.log(4);

// 输出结果是  
1  
2 
4
  1. 首先是new一个Promise对象,会立即执行回调函数,正好回调函数中都是同步任务,所以输出1 2

  2. promise.then()是一个微任务,放入微任务队列暂时不管

  3. 执行同步任务输出4

  4. 同步任务执行完毕,取出微任务promise.the(),但是这个promise对象在创建的时候没有返回任何状态值,因此then()中的回调函数无法执行,整个代码执行完毕

const promise1 = new Promise((resolve, reject) => {
    console.log('promise1')
    resolve('resolve1')
})
const promise2 = promise1.then(res => {
    console.log(res)
})
console.log('1', promise1);
console.log('2', promise2);

// 输出结果是:  
promise1
1 Promise { 'resolve1' }
2 Promise { <pending> }
resolve1
  1. new一个promise1,回调函数立即执行,执行输出语句,执行resolve()使得promise1有了resolved状态值resolve1

  2. promise1.then()是微任务,暂存微任务队列

  3. 执行两个同步任务输出语句,输出promise对象实则就是输出当前Promise对象的状态以及状态值,输出结果是以对象的形式呈现

  4. 同步任务执行完毕,取出微任务执行,promise1.then()中的res接收的是resolved值【resolve1】,所以输出resolve1

  5. 代码全部执行完毕

  6. 补充一点:promise2的作用是用来接收then()中返回一个新的Promise对象,但是实际上没有返回Promise对象给promise2

未完待续…(2021.10.02)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值