首页 > 其他分享 >Promise 基础知识及手写简易Promise

Promise 基础知识及手写简易Promise

时间:2023-03-25 23:44:59浏览次数:33  
标签:resolve 基础知识 p1 let promise reject Promise 手写

promise

引用类型Promise,翻译期约(承诺),是一种异步编程结局方案。当我们许下承诺,代表着未来的不确定性(pending),当我们实现时,承诺变为成功(fulfilled)。当我们未能实现时,承诺变为失败(rejected)。

通过new实例化,创建时传入executor函数参数,此时承诺状态为待定。
let promise = new Promise(()=>{})

一、承诺的状态机

  • 待定 pending
  • 成功 fulfilled
  • 失败 rejected

待定是承诺的初始状态,处于待定时可以兑现承诺,变为成功或失败。但是兑现承诺这一过程是不可逆的,且仅能改变一次。promise是无法通过js访问的,因为故意为了和同步代码隔离开。

二、执行器executor

执行器函数是同步执行的,并且在创建完成后立即执行。

let p1 = new Promsie((resolve,reject) => console.log('promise'))
console.log('hello')

承诺的状态只能在内部执行器中改变,控制承诺的状态改变是通过调用两个函数参数实现。这两个函数通常命名为resolve()和reject()。

resolve()

调用resolve()会将状态从pending切换到成功,调用resolve(value)时可以传入一个value

let promise = new Promise((resolve, reject)=>{
  console.log('promise')
  resolve("成功");	// 调用 resolve 方法
})
console.log('ok', promise)

// 执行结果:
promise
ok Promise { '成功' }

reject()

调用reject()则会将状态从pending切换到失败并且抛出错误,调用reject(reason)时可以传入一个reason

let promise = new Promise((resolve, reject)=>{
  console.log('promise')
  reject("失败");	// 调用 reject 方法
})
console.log('ok', promise)

// 执行结果:
promise
ok Promise { <rejected> '失败' }

三、Promise 静态 API(类方法)

Promise 共有 4 个静态方法,分别是:resolve、reject、all、race;

Promise.resolve()

创建并返回一个成功状态的 Promise 实例,并将传入的参数作为返回值

let p1 = new Promise((resolve,reject)=> resolve())
let p2 = Promise.resolve()  // 两种方法一样,直接实例化一个成功的Promise

使用这个静态方法可以将任意值转换为一个Promise。

// Chrome控制台打印测试

// 返回传入传入Promise的第一个参数
Promise.resolve()
// Promise {<fulfilled>: undefined}
Promise.resolve(666)
// Promise {<fulfilled>: 666}

// 多余参数会被忽略
Promise.resolve(1,2,3)    
// Promise {<fulfilled>: 1}

// 传入的参数为Promise,那就是个空包装,Promise.resolve()是一个幂等的方法
// *tips:幂等函数,或幂等方法,是指可以使用相同参数重复执行,并能获得相同结果的函数。 这些函数不会影响系统状态,也不用担心重复执行会对系统造成改变*
Promise.resolve(Promise.resolve(99999))
// Promise {<fulfilled>: 99999}

// 由于幂等性会保留传入Promise的状态
Promise.resolve(new Promise(()=>{}))
// Promise {<pending>}

// 错误对象也能包装,虽然有点反常理
Promise.resolve(new Error('出错啦'))
// Promise {<fulfilled>: Error: 出错啦
//     at <anonymous>:1:17}

Promise.reject()

Promise.reject():创建并返回一个失败状态的 Promise 实例,并异步抛出一个错误

let p1 = new Promise((resolve,reject)=> reject())
let p2 = Promise.reject()  // 两种方法一样,直接实例化一个失败的承诺
Promise.reject()
// Promise {<rejected>: undefined}
// VM1521:1 Uncaught (in promise) undefined 
Promise.reject(666)
// Promise {<rejected>: 666}
// VM1580:1 Uncaught (in promise) 666 
Promise.reject(1,2,3)
// Promise {<rejected>: 1}
// VM1647:1 Uncaught (in promise) 1 

// 这里有所不同,Promise.reject()并没有幂等性
Promise.reject(Promise.resolve(99999))
// Promise {<rejected>: Promise}
// VM1699:1 Uncaught (in promise) Promise {<fulfilled>: 99999}

Promise.all()

Promise.all():传入一个由Promise组成的数组,返回一个新的Promise实例,只要数组中有一个失败就返回失败的Promise实例。

// 两个全部成功后才会返回成功的Promise,如果出现pending则返回pending
let ppp =Promise.all([
  Promise.resolve(),
  new Promise((resolve,reject)=> setTimeout(()=>resolve(),1000))
])

console.log(ppp);  // Promise {<pending>}

setTimeout(() => {
    console.log('1秒后',ppp);  // Promise {<fulfilled>: Array(2)}
}, 1000);


// 只要有一个失败,则返回失败的Promise
Promise.all([
  Promise.resolve(3),
  Promise.reject(666),
  Promise.resolve(4)
])
// Promise {<rejected>: 666}


Promise.all([
  Promise.resolve(3),
  Promise.resolve(),
  Promise.resolve(4),
])
// Promise {<fulfilled>: Array(3)}
// [[Prototype]]: Promise
// [[PromiseState]]: "fulfilled"
// [[PromiseResult]]: Array(3)
// 0: 3
// 1: undefined
// 2: 4

// 如果有Promise拒绝,则返回失败并将参数作为错误的原因
// 以下操作没有报出错误,说明第二个Promise仍旧进行了,只是被静默处理了。
let pp = Promise.all([
  Promise.reject(3),
  new Promise((resolve,reject)=> setTimeout(()=> reject(),1000))
])
pp.catch(reason => setTimeout(()=> console.log(reason)))

Promise.race()

Promise.race():传入一个由Promise组成的数组,返回一个最先成功或拒绝的Promise。无论最先落定的是成功或拒绝的,都会包装值或理由并返回新的Promise。

// 成功先发生的,超时后失败被忽略
let p1 = Promise.race([
  Promise.resolve(666),
  new Promise((resolve,reject)=> setTimeout(()=>reject(),1000))
])
// 失败先发生的,超时后成功被忽略
let p2 = Promise.race([
  Promise.rejct(666),
  new Promise((resolve,reject)=> setTimeout(()=>resolve(),1000))
])
// Promise {<fulfilled>: 1}
let p3 = Promise.race([
  Promise.resolve(1),
  Promise.resolve(2),
  Promise.resolve(3)
])
// 如果有Promise拒绝,之后拒绝的Promise不会影响最终Promise的理由
// 以下操作没有报出错误,说明第二个Promise仍旧进行了,只是被静默处理了。
let 4 = Promise.race([
  Promise.reject(3),
  new Promise((resolve,reject)=> setTimeout(()=> reject(),1000))
])
pp.catch(reason => setTimeout(()=> console.log(reason)))

四、Promise 实例 API(原型方法)

Promise.prototype.then()

then()方法接受两个函数参数:onResolved处理程序和onRejected处理程序,分别在Promise进入成功或失败时执行。then()方法返回一个新的Promise实例。

  • 如果then指定的回调返回的是非Promise值a,走成功,成功的值是a
  • 如果then指定的回调返回的是Promise实例,新的Promise状态和值和上次一致(幂等方法)。
  • 如果then指定的回调返回的是新Promise状态为rejected,则失败的reason为异常
let p1 = new Promise((resolve,reject)=> setTimeout(()=>reject(),3000))
p1.then(null, ()=> setTimeout(()=>console.log(666),1000)) // 良好的习惯,空值占位
// 666
// Promise {<rejected>: undefined}

onResolved(),onResolved处理程序返回的值会被Promise.resolve()包装生成新的的Promise

let p1 = Promise.resolve('hello')
// 如果没有显式的返回值,若then指定的回调是Promise实例,新的Promise的状态和值会直接传递
let p2 = p1.then()  // Promise {<fulfilled>: 'hello'}   
let p3 = p1.then(()=> undefined)  // Promise {<fulfilled>: undefined}
let p4 = p1.then(()=> {})  // Promise {<fulfilled>: undefined}
let p5 = p1.then(()=> Promise.resolve())  // Promise {<fulfilled>: undefined}

// 如果有显示的返回值
let p6 = p1.then(()=> 'bar')  // Promise {<fulfilled>: 'bar'}
let p7 = p1.then(()=> Promise.resolve('bar')) // Promise {<fulfilled>: 'bar'}

// 如果传入是Promise实例,则新的Promise状态和值和上次一致(幂等方法)
let p8 = p1.then(()=> new Promise(() => {}))  // Promise {<pending>}
let p9 = p1.then(()=> Promise.reject()) // Promise {<rejected>: undefined}

// 抛出异常会返回拒绝的Promise
let p10 = p1.then(()=> { throw 'baz' }) // Promise {<rejected>: 'baz'}
// 注意!返回错误值不会触发上面的拒绝行为,而是把错误对象包装在一个成功的Promise中
let p11 = p1.then(()=> Error('qux'))  //Promise {<fulfilled>: Error: qux

onRejected()同onResolved类似,onRejected处理程序返回的值会被Promise.resolve()包装

let p1 = Promise.reject('foo')

let p2 = p1.then()  // Promise {<rejected>: 'foo'}
let p3 = p1.then(null, ()=> undefined)  // Promise {<fulfilled>: undefined}
let p4 = p1.then(null, ()=> {})  // Promise {<fulfilled>: undefined}
let p5 = p1.then(null, ()=> Promise.resolve())  // Promise {<fulfilled>: undefined}
let p6 = p1.then(null, ()=> 'bar')  // Promise {<fulfilled>: 'bar'}
let p7 = p1.then(null, Promise.resolve('bar'))  // Promise {<rejected>: 'foo'}
let p8 = p1.then(null, ()=> new Promise(()=> {}))  // Promise {<pending>}
let p9 = p1.then(null, ()=> Promise.reject())  // Promise {<rejected>: undefined}
let p10 = p1.then(null,()=> { throw 'baz'})  // Promise {<rejected>: 'baz'}
let p11 = p1.then(null, ()=> Error('qux'))  // Promise {<fulfilled>: Error: qux

Promise.prototype.catch()

catch()方法用于给Promise添加失败的回调。catch方法只接受一个参数:onRejected处理程序。catch相当于一个语法糖,调用他相当于Promise.prototype.then(null, onRejected)

let p = Promise.reject()
let onRejected = (e)=>{
    setTimeout(()=> console.log('rejected'),1000)
}
// 以下两种方式相同
p.then(null,onRejected)
p.catch(onRejected)

catch方法返回一个新的实例

let p1 = new Promise(()=>{})  // 
let p2 = p1.catch() // Promise {<pending>}

Promise.prototype.finally()

finally()方法用于给Promise添加onFinally处理程序,这个程序在Promise转化为成功或失败时都会执行。onFinally这个程序设计为与promise状态无关的方法,所以它没法知道promise是成功还是失败,它只会表现为父级Promise的传递,这个方法主要用于添加清理代码。

let p1 = Promise.resolve()
let p2 = Promise.reject()
let onFinally = function(){
  setTimeout(()=>{console.log('fianlly')},1000)
}
p1.finally(onFinally) // fianlly
p2.finally(onFinally) // finally

五、简单的实现的Promise

        // 定义promise中的三种状态
        const STATUS_PENDING = "pending";
        const STATUS_FULFILLED = "fulfilled";
        const STATUS_REJECTED = "rejected";

        // 定义promise的类
        class myPromise {
            //class的构造函数,接受新建实例时的参数:executor在promise中是一个函数
            constructor(executor) {
                //初始化该class中的初始状态
                this.status = STATUS_PENDING;
                //定义class中成功(res)和失败(err)时的变量值
                this.res = "";
                this.err = "";

                //promis异步中最重要的异步,定义成功和错误函数存储的数组,存放异步时还没有执行的操作
                this.onResCallbacks = [];
                this.onErrCallbacks = [];

                //定义该构造函数constructor定义域中的变量resolve
                let resolve = (res) => {
                    // 首先判断该class中的状态,只有状态为pending时才能转化class转态为fulfilled或者rejected
                    if (this.status === STATUS_PENDING) {
                        //修改class的转态为fulfilled,也就表示不会转进行其他转态的转化了
                        this.status = STATUS_FULFILLED;
                        //将成功(resolve)状态下的值赋给class的成功返回res
                        this.res = res;
                        //此时状态由pending转为fulfilled,执行之前在then中存放的需要执行的异步操作,promise的then中参数res接受结果
                        this.onResCallbacks.forEach(fn => fn());
                    }
                };

                //定义该构造函数constructor定义域中的变量reject
                let reject = (err) => {
                    // 首先判断该class中的状态,只有状态为pending时才能转化class转态为fulfilled或者rejected
                    if (this.status === STATUS_PENDING) {
                        //修改class的转态为rejected,也就表示不会转进行其他转态的转化了
                        this.status = STATUS_REJECTED;
                        //将失败(reject)状态下的值赋给class的失败返回err
                        this.err = err;
                        //此时状态由pending转为rejected,执行之前在catch中存放的需要执行的异步操作,promise的catch中参数err接受结果
                        this.onErrCallbacks.forEach((fn) => fn());
                    }
                };

                //按照promise中的逻辑,在调用时就立即执行了,所以在手写的myPromise创建构造函数constructor时就执行executor
                try {
                    //执行参入的函数,并将上述定义的resolve和reject作为参数传入
                    executor(resolve, reject);
                } catch (err) {
                    //报错时调用失败的状态函数
                    reject(err);
                }
            }

            //在class中定义promise的成功状态接收函数then,按照promise逻辑,then中传入的一般都是一个函数
            then(onRes = () => { }) {
                //如果是异步的,此时在constructor中status的状态还没变成fulfilled,所以会跳过onRes调用,没有返回
                if (this.status === STATUS_FULFILLED) {
                    onRes(this.res);
                }
                //但是我们将此时的异步放入数组存放
                if (this.status === STATUS_PENDING) {
                    this.onResCallbacks.push(() => onRes(this.res));
                }
                //这步操作保证了then和catch能够在同级一起"."调起,当then上述操作完后,返回class实例,便可以接在后面继续调用catch
                return this;
            }

            //在class中定义promise的失败状态接收函数catch,按照promise逻辑,catch中传入的一般都是一个函数
            catch(onErr = () => { }) {
                //如果是异步的,此时在constructor中status的状态还没变成rejected,所以会跳过onErr调用,没有返回
                if (this.status === STATUS_REJECTED) {
                    onErr(this.err);
                }
                //但是我们将此时的异步放入数组存放
                if (this.status === STATUS_PENDING) {
                    this.onErrCallbacks.push(() => onErr(this.err));
                }
                //这步操作保证了then和catch能够在同级一起"."调起,当catch上述操作完后,返回class实例,便可以接在后面继续调用then
                return this;
            }
        }

        //调用自己手写的promise
        new myPromise((resolve, reject) => {
            // console.log("进入了手写的promise");
            //用setTimeOut模拟异步操作
            setTimeout(() => {
                if (false) {
                    resolve("输出成功结果resolve");
                } else {
                    reject("输出失败结果reject");
                }
            }, 2000); //按照js的特性,此时不会等待异步完成,直接调用then或者catch
        })
            .then((res) => {
                console.log("then:", res);
            })
            .catch((err) => { //return this具体作用体现在这里
                console.log("catch:", err);
            });

标签:resolve,基础知识,p1,let,promise,reject,Promise,手写
From: https://www.cnblogs.com/wanglei1900/p/17255961.html

相关文章

  • Java进阶基础知识点(包及final关键字、常量)
    一:包的概述包就是文件夹,用来管理各种不同功能的Java类,方便后期代码维护。包的命名规则:公司域名的反写+包的作用,需要全部英文小写,见名知意。例如;com.51cto.domain.student.......
  • Java基础知识流程与示例
    一、Java知识流程Java语言特点和发展历史数据类型、变量和常量运算符和表达式控制语句(if、switch、for、while等)数组和字符串面向对象编程(类和对象、继承、封装、多......
  • 飞机基础知识一 1.3二维平面飞机运动学模型
    飞机基础知识一1.3二维平面飞机运动学模型目录飞机基础知识一1.3二维平面飞机运动学模型运动学方程程序实现完整代码效果运动学方程在二维平面上将飞机视为一个质点......
  • docker 必会基础知识
    Docker知识汇总docker安装安装地址windows:https://desktop.docker.com/win/stable/amd64/Docker%20Desktop%20Installer.exe?utm_source=docker&utm_medium=webreferra......
  • QT | 手写代码实现HelloWorld
    QT|手写代码实现HelloWorld文章目录`QT`|手写代码实现`HelloWorld`1.新建工程1-1.main.cpp文件1-2.mainwindow.h和mainwindow.cpp文件1-3.编译、运行2.编码实现简易的......
  • Promise源码和静态方法
    Promise源码index.html文件进行测试,Promise.js文件写源码    Promise是一个类,我们使用class进行Promise的声明jsclassPromise{}html<scriptsrc="./Pro......
  • C语言基础知识
    1、变量类型   字符型--char--所占字节(1)   整型--int--所占字节(4)   短整型--short--所占字节(2)   长整型--long--所占字节(4)   更长的整形--longlo......
  • 通信基础知识-名词解释
    AWGN:加性高斯白噪声(AWGN)是一个数学模型,用于仿真发射机和接收机之间的信道。这个模型是线性增加的宽带噪声,具有恒定的频谱密度和高斯分布的幅度。AWGN不适用于衰落、互......
  • 异步编程解决方案 Promise
    1.回调地狱2.Promise的使用3.Promise的状态4.Promise的结果5.Promise的then方法6.Promise的catch方法7.回调地狱的解决方案1.回调地狱回调地狱:在......
  • 计算机核心基础知识
    目录’一、编程与编程语言(1)、什么是语言(2)、什么是编程(3)、什么是编程语言二、计算机本质三、计算机五大组成部分(1)、控制器(2)、运算器(3)、存储器(4)、输出设备(5)......