ES6异步处理方式---Promise知识点总结

243 阅读6分钟

前言

本文整理了Promise相关基础和一些方法的底层原理实现,如果对答案有不一样见解的同学欢迎评论区补充讨论,当然有问题,也欢迎在评论区指出。

切记:Promise很重要很重要很重要,那Promise是什么?又为什么重要?有同学就说了,Promise可以处理异步,那Promise又是如何处理异步的?常用的方法有哪些?它们的作用是什么?

引用加参考:

Promise就是这么简单,你听懂了吗?

image.png

1、处理异步的方式

(1)回调函数

概念:被作为实参传入另一函数,并在该外部函数内被调用(有先后顺序),用以来完成某些任务 的函数,称为回调函数。

缺点:容易出现回调地狱

function b(value) {
    var bb = "everyone";
    console.log(value + bb);
}
function a(callback) {
    let value = "hello ";
    setTimeout(() => {
        callback(value);
    }, 1000);
}
a(b);
//这是一个异步回调,1秒钟之后才会执行b函数(回调函数)

(2)Promise

ES6新增处理异步的一种语法,详细请往下看(第二大节往后)

(3)async、await

async 函数是 Generator 函数的语法糖。async await就等于Generator+自动执行器,其底层原理实现juejin.cn/post/699723…

asyncawait关键字让我们可以用一种更简洁的方式写出基于Promise的异步行为,而无需刻意地链式调用promise

2、Promise是什么,为什么重要?

Promise 是异步编程的一种解决方案:

  • Promise是一个对象,它让您能够把异步操作最终的成功返回值或者失败原因和相应的处理程序关联起来。 这样使得异步方法可以像同步方法那样返回值:异步方法并不会立即返回最终的值,而是会返回一个 promise,以便在未来某个时候把值交给使用者。

  • Promise有三种状态:pending(等待态),fulfiled(成功态),rejected(失败态) ;状态一旦改变,就不会再变。创造Promise实例后,它会立即执行,通过.then()或.catch()返回成功或失败结果。

3、Promise的基本使用

let promise = new Promise((resolve,reject)=>{
    setTimeout(()=>{
        console.log('value1')
        resolve('value2')
        reject('value3')
    },1000)
})

// 只要调用promise就会执行,但是resolve里的值只有.then()方法调用打印才可
// 即 前者是在异步操作执行时打印,后者是在异步操作执行完成resolve时,.then()调用时打印
// promise.then() //value1
promise.then(res=>{
    console.log(res) //value2
}).catch(err=>{
    console.log(err)//value3
})

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

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

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

4、Promise类实现

具体实现步骤:

  1. Promise 是一个类,在执行这个类的时候会传入一个执行器,这个执行器会立即执行
  2. Promise 会有三种状态
    • Pending 等待
    • Fulfilled 完成
    • Rejected 失败
      • 状态只能由 Pending --> Fulfilled 或者 Pending --> Rejected,且一但发生改变便不可二次修改;
  1. Promise 中使用 resolve 和 reject 两个函数来更改状态;
  2. then 方法内部做但事情就是状态判断
    • 如果状态是成功,调用成功回调函数
    • 如果状态是失败,调用失败回调函数
// 先定义三个常量表示状态
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

// 新建 MyPromise 类
class MyPromise {
    constructor(executor){
        // executor 是一个执行器,进入会立即执行
        // 并传入resolve和reject方法
        executor(this.resolve, this.reject)
    }

    // 储存状态的变量,初始值是 pending
    status = PENDING;
    // 成功之后的值
    value = null;
    // 失败之后的原因
    reason = null;

    // resolve和reject为什么要用箭头函数?
    // 如果直接调用的话,普通函数this指向的是window或者undefined
    // 用箭头函数就可以让this指向当前实例对象
    
    // 更改成功后的状态
    resolve = (value) => {
        // 只有状态是等待,才执行状态修改
        if (this.status === PENDING) {
            // 状态修改为成功
            this.status = FULFILLED;
            // 保存成功之后的值
            this.value = value;
        }
    }

    // 更改失败后的状态
    reject = (reason) => {
        // 只有状态是等待,才执行状态修改
        if (this.status === PENDING) {
            // 状态成功为失败
            this.status = REJECTED;
            // 保存失败后的原因
            this.reason = reason;
        }
    }

    then(onFulfilled, onRejected) {
        // 判断状态
        if (this.status === FULFILLED) {
            // 调用成功回调,并且把值返回
            onFulfilled(this.value);
        } else if (this.status === REJECTED) {
            // 调用失败回调,并且把原因返回
            onRejected(this.reason);
        }
    }
}

// 引入我们的 MyPromise.js
const promise = new MyPromise((resolve, reject) => {
    resolve('success')
    reject('err')
})

promise.then(value => {
    console.log('resolve', value)
}, reason => {
    console.log('reject', reason)
})

// 执行结果:resolve success

5、Promise.prototype.then()链式调用

var p1 = function (){
    new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('red')
        }, 1000);
    }).then(res => {
        return new Promise((resolve, reject) => {
            console.log(res)
            setTimeout(() => {
                resolve('green')
            }, 2000);
        })
    }).then(res => {
        return new Promise((resolve, reject) => {
            console.log(res)
            setTimeout(() => {
                resolve('yellow')
            }, 3000);
        })
    }).then(res => {
        console.log(res);
    })
}

catch() 方法返回一个Promise ,并且处理拒绝的情况。它的行为与调用Promise.prototype.then(undefined, onRejected) 相同,仅仅是不同状态,处理结果不同

6、Promise.resolve()

Promise.resolve(...)可以接收一个值或者是一个Promise对象作为参数。

  • 当参数是普通值时,它返回一个resolved状态的Promise对象,对象的值就是这个参数;
  • 当参数是一个Promise对象时,它直接返回这个Promise参数
const promise1 = Promise.resolve( 1 );
const promise2 = Promise.resolve( promise1 );
console.log(promise1===promise2)//true
const promise1 = Promise.resolve( 1 );
const promise4 = new Promise(function(resolve, reject){
    resolve(promise1);
});

promise4.then(res=>{
    console.log('promise4:', res)
});
promise1.then(res=>{
    console.log('promise1:', res)
})
// resolve(promise1)需要'拆箱',这个过程是异步的
// 先打印promise1:1
// 再打印promise:2

7、Promise方法总结

以下方法定义来源于MDN官方定义(权威)

具体方法底层原理实现可以看看这篇文章:juejin.cn/post/699731…

(1)Promise.all() 方法

接收一个promise的iterable类型(注:Array,Map,Set都属于ES6的iterable类型)的输入,并且只返回一个Promise实例,那个输入的所有promise的resolve回调的结果是一个数组(这是在全部执行成功前提下)

注意⚠️:只要任何一个输入的promise的reject回调执行或者输入不合法的promise就会立即抛出错误,并且reject的是第一个抛出的错误信息

注意⚠️:而Promise.allSettled()方法,不管成功失败的结果,都返回一个数组

(2)Promise.race()方法

简单来说就是赛跑-----Promise.race([p1, p2, p3])返回那个最快完成的结果,不管结果本身是成功状态还是失败状态。

注意⚠️:Promise.any()是接收一个Promise可迭代对象,返回那个最先成功的结果。如果没有一个 promise 成功(即所有的 promises 都失败/拒绝),就返回一个失败的 promise


八、Promise值穿透

new Promise((resolve, reject) => {
    reject(1) //失败状态
})
    .then(value => {
        console.log('成功', value);
    }, reason => {
        console.log('失败', reason); //失败 1;无返回值、默认返回成功状态,状态值为undefined
    })
    .then(value => {
        console.log('成功', value); //成功 undefined
    }, reason => {
        console.log('失败', reason);
    })
    .then(value => {
        console.log('成功', value); //成功 undefined
    }, reason => {
        console.log('失败', reason);
    })
// 打印结果
// 第一行:失败 1;
// 第二行:成功 undefined
// 第三行:成功 undefined

总结

觉得写得好的,对你有帮助的,可以分享给身边人,知识越分享越多,千万不要吝啬呀

后续更新promise相关基础和一些方法的底层原理实现总结,请关注我,整理好,分享给你们,我们一起学前端。