手写一个Promise后,全懂了

手写实现promise以及promise.all和promise.race 之前写的一个promise太多了,面试写下来的话。。。。emmm,所以在复习时又写一个简单的。 promise class Promsie { constructor(fn) { //三个状态 this.status = 'pending', this.resolve = undefined; this.reject = undefined; let resolve = value => { 阅读详情

目录

1. 通过创建一个Promise对象,初始化一个Promise类

2.状态的限制

3. ‘.then’的写法:

4. 异步处理

5.实现链式调用


1. 通过创建一个Promise对象,初始化一个Promise类

const P = new Promise((resolve,reject) => {
    //这里面的代码会立即执行,在PromiseA+规范中叫做excutor,里面提供了resolve和reject两个方法

    //在promise内部通常会执行一个异步操作,操作的结果有成功(fulfilled)和失败(rejected)
    resolve();//将pending 状态改变为 fulfilled
    reject();//将pending 状态改变为 rejected
})

初始化Promise类:

class Promise{
    constructor(excutor){
        this.state = 'pending';  //初始化这个Promise的状态
        this.value = undefined;  //初始化这个Promise成功时需要返回的值
        this.reason = undefined; //初始化这个Promise失败时返回的值

        //在执行resolve的时候将状态从pending改变为fulfilled,并记录调用resolve时传入的值
        let resolve = (val) => {
            //这里的val是指在调用resolve时传入的值
            this.state = 'fulfilled'    //改变这个Promise的状态
            this.value = val            //更新这个Promise的值
        }
        //reject同上
        let reject = (reason) => {
            this.state = 'rejected'
            this.reason = reason
        }
        try{
            excutor(resolve,reject) //立即执行
        }catch(err){
            reject(err)//执行excutor报错的时候也要返回reject
        }           
    }
}

初始化完成之后尝试调用一下新建的这个Promise类

    const P = new Promise((resolve,reject) => {

        resolve(200);

        reject(500);

    })

    console.log(P);

 得到的结果为:

 可以看到我们的resolve和reject都被调用了,因为reason和value都有值,但是state被覆盖了,众所周知,在一个标准的Promise中,是存在 “状态凝固” 的,也就是说,pending要么通过resolve变成fulfilled,要么通过reject变成rejected。不能这样被后面调用的给覆盖了状态,因此我们需要在更改状态的代码片段中加一点限制。

2.状态的限制

let resolve = (val) => {
    //只有当状态是pending时才能改变和更新值
    if(this.state === 'pending'){
        this.state = 'fulfilled'
        this.value = val
    }    
}

//reject同上
let reject = (reason) => {
    if(this.state === 'pending'){
        this.state = 'rejected'
        this.reason = reason
    } 
}

这样就完成了对状态的限制,接下来就是对.then方法的调用。在PromiseA+规范中,.then方法是写在promise的原型上的,而且.then方法可以传入两个参数,第一个是成功后的回调,第二个是失败后的回调。

const P = new Promise((resolve,reject) => {
    resolve(200) //返回成功的状态,更新这个promise对象值为200
})

//当回调是成功时,走第一个箭头函数,并将200赋值给res
//当回调是失败时,走第二个箭头函数,将失败信息赋值给err
P.then(res => {},err => {})

3. ‘.then’的写法:

class Promise{
    //以下为原型部分
    constructor(excutor){
    //以下是实例部分
        ...
    }

    /*then:调用Promise对象
        @params: 
            onFulFilled:成功时的回调
            onRejected:失败时的回调
        @return:
            Promise对象的值
    */
    then(onFulFilled,onRejected){
        //判断Promise对象的状态
        if(this.state === 'fulfilled'){
            onFulFilled(this.value)    //将resolve的值传给res
        }
        if(this.state === 'rejected'){
            onRejected(this.reason)    //将reject的值传给err
        }
    }
}

const P = new Promise(resolve => {
    resolve(200)
})

const P2 = new Promise((resolve,reject) => {
    reject(500)
})

P.then(res => {
    console.log(res) //=>200
})

P2.then(res => {},err =>{
    console.log(err) //=>500
})

此时的.then已经完成的差不多了,还剩下最后一个判断,异步处理,在上面的代码中,如果我们在new Promise对象的时候,往Promise内部添加了异步处理,那么.then方法就会先走,然后再回来判断这个Promise对象的状态:

    const P = new Promise(resolve => {
      setTimeout(() => { //设置异步定时器
        resolve(200)
      },2000)
    })

    P.then(res => {
      console.log(res);//这里本应该输出200,但是并没有输出
    })

    console.log(P);

打印p的结果为:

 这会导致我们的.then方法不能顺利完成自己应该做的事情。

4. 异步处理

因此我们需要将.then方法中的两个回调(onFulFilled 和 onRejected)设置成,当状态改变时在执行回调函数。所以我们需要在excutor中初始化两个数组用来接受不同状态的回调函数,并且从.then中传那些回调过来

class Promise{
    constructor(excutor){
        this.state = 'pending';  
        this.value = undefined;
        this.reason = undefined;
        this.onResolveCallBack = [];        //存放是成功回调函数的数组
        this.onRejectCallBack = [];         //存放是失败回调函数的数组

        let resolve = (val) => {
            this.state = 'fulfilled'    
            this.value = val  
            //当执行到resolve的时候,状态改变完成,执行onResolveCallBack里存放的成功回调函数
            this.onResolveCallBack.forEach(fn => fn())         
        }

        let reject = (reason) => {
            this.state = 'rejected'
            this.reason = reason
            //reject同上
            this.onRejectCallBack.forEach(fn => fn())
        }
        try{
            excutor(resolve,reject)
        }catch(err){
            reject(err)
        }     
    }

    then(onFulFilled,onRejected){
        if(this.state === 'fulfilled'){
            onFulFilled(this.value)    
        }
        if(this.state === 'rejected'){
            onRejected(this.reason)    
        }
        if(this.state === 'pending'){
            this.onResolveCallBack.push(()=>{    //向onResolveCallBack中存入成功的回调函数
                onFulFilled(this.value)
            })
            this.onRejectCallBack.push(() => {
                onRejected(this.reason)          //向onRejectCallBack中存入失败的回调函数
            })
        }
    }
}

验证一下能不能实现异步处理效果:

    const P = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve(200)
      }, 3000);
    })

    P.then(res => {
      console.log(res); //=>200
      console.log(P); //=>state:fulfilled;value:200
    })

 至此,成功实现了Promise.then的异步操作

5.实现链式调用

实现了.then的异步操作之后就是链式调用的问题了,按照现在的 代码,我们无法做到在.then后再次执行.then的操作,如:

const P = new Promise((resolve,reject) => {
    resolve(200)
})

P.then(res => {
    console.log(res)
    return 201
}).then(res => {
    console.log(res) //此处应该输出201,但是目前这里并不会进行输出
})

因为.then的操作并没有返回一个Promise对象,因此无法在执行链式调用操作,我们必须让.then的结果是一个Promise对象,并且不能返回本身(P)

class Promise{
        ...    
    }

    then(onFulFilled,onRejected){
        //let promise2 用来接受需要返回的promise对象
        let promise2 = new Promise((resolve,reject) => {
            if(this.state === 'fulfilled'){
                //let x 接收onFulFilled的返回值
                let x = onFulFilled(this.value)    
            }
            if(this.state === 'rejected'){
                //let y 接收onRejected的返回值
                let y = onRejected(this.reason)    
            }
            if(this.state === 'pending'){
                this.onResolveCallBack.push(()=>{
                    onFulFilled(this.value)
                })
                this.onRejectCallBack.push(() => {
                    onRejected(this.reason) 
                })
            }
        })
        return promise2
    }
}

此外,我们需要对onFulFilled和onRejected的返回值进行判断

class Promise{
        ...    
    }

    then(onFulFilled,onRejected){
        //let promise2 用来接受需要返回的promise对象
        let promise2 = new Promise((resolve,reject) => {
            if(this.state === 'fulfilled'){
                //这里的代码是与let promise2同步进行,因此需要加上异步操作避免无法获取到promise2
                setTimeout(()=>{
                    //let x 接收onFulFilled的返回值
                    let x = onFulFilled(this.value)
                    resolvePromise(promise2,x,resolve,reject)   //判断x的返回值 
                },0)
            }
            if(this.state === 'rejected'){
                //同上
                ...    
            }
            if(this.state === 'pending'){...}
        })
        return promise2
    }
}

/*
    resolvePromise(promise2,x,resolve,reject)判断.then的返回值
    @params:
        promise2:调用.then函数的对象本身
        x:.then的返回值
        resolve、reject:处理方法
    @return:
        根据.then的返回值返回不同的处理结果
        1).then的返回值是本身,控制台报错
        2).then的返回值是Promise对象,根据Promise对象的状态调用resolve或者reject
        3)返回是普通值,直接调用resolve
*/

function resolvePromise(promise2,x,resolve,reject){
    //判断.then的返回值是否等于本身
    if(x === promise2){
        console.err(new TypeError('Chaining cycle detected for promise #<Promise>'))
    }
    //判断x是否属于Promise对象,如果是,根据其状态来返回结果,如果不是,直接调用resolve
    if(x instanceof Promise){
        /*x.then((value)=>{
          resolve(value)
        },err => {
          reject(err)
        })*/
        //上面的片段可以简写为:
        x.then(resolve,reject)
    }else{
        resolve(x)
     }
}

//reject的函数处理同上
function rejectPromise(promise2,y,resolve,reject){...}

至此,一个较为完整的Promise对象就写好了

代码完全版:

    class Promise {
      constructor(excutor) {
        this.state = 'pending';
        this.value = undefined;
        this.reason = undefined;
        this.onResolveCallBack = [];
        this.onRejectCallBack = [];

        let resolve = (value) => {
          if (this.state === 'pending') {
            this.state = 'fulfilled'
            this.value = value
            this.onResolveCallBack.forEach(fn => fn())
          }
        }
        let reject = (reason) => {
          if (this.state === 'pending') {
            this.state = 'rejected'
            this.reason = reason
            this.onRejectCallBack.forEach(fn => fn())
          }
        }
        try {
          excutor(resolve, reject)
        } catch (err) {
          reject(err)
        }
      }

      then(onFulFilled, onRejected) {
        let promise2 = new Promise((resolve, reject) => {
          if (this.state === 'fulfilled') {
            setTimeout(() => {
              let x = onFulFilled(this.value)
              resolvePromise(promise2, x, resolve, reject)
            }, 0);
          }
          if (this.state === 'rejected') {
            setTimeout(() => {
              let y = onRejected(this.reason)
              rejectPromise(promise2, y, resolve, reject)
            }, 0);
          }
          if (this.state === 'pending') {
            this.onResolveCallBack.push(() => {
              onFulFilled(this.value)
            })
            this.onRejectCallBack.push(() => {
              onRejected(this.reason)
            })
          }
        })
        return promise2
      }
    }

    function resolvePromise(promise2, x, resolve, reject) {
      if (x === promise2) {
        console.err(new TypeError('Chaining cycle detected for promise #<Promise>'))
      }
      if (x instanceof Promise) {
        x.then(resolve, reject)
      } else {
        resolve(x)
      }
    }

    function rejectPromise(promise2, y, resolve, reject) {
      if (y === promise2) {
        console.err(new TypeError('Chaining cycle detected for promise #<Promise>'))
      }
      if (y instanceof Promise) {
        y.then(resolve, reject)
      } else {
        reject(y)
      }
    }

测试:

    const P = new Promise((resolve, reject) => {
      resolve(200);
      reject(404);
    })

    P.then(res => {
      console.log(res);
      return 500
    }).then(res => {
      console.log(res);
    })

结果为:  链式调用没问题。

Javascript 手写一个Promise 回调函数中嵌套回调)(1)对象的不受外界影响。Promisepending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。(2)。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为。如果改变已经发生了,你再对Promise 阅读详情

相关推荐

Fedora 41上安装钉钉7.6.25,我踩过的那些依赖坑和最终解决方案

本文详细记录了在Fedora 41上安装钉钉7.6.25版本的全过程,包括解决依赖问题、转换deb包为rpm格式、处理libm.so.6错误等关键步骤。通过分享这些实用技巧和最终解决方案,帮助Linux用户顺利在Fedora系统上运行钉钉客户端,提升工作效率。

weixin_30485379的博客 163

教你如何手写一个Promise

promise的进阶,手写一个自己的promise

ose_huang的博客 9941

C#实战:从零搭建Vosk离线语音转文字系统

本文手把手教你用C#构建离线语音转文字系统,基于NAudio和Vosk实现全流程开发。首先介绍环境搭建,包括NuGet包安装和中文模型配置,强调16kHz单声道音频格式的关键性。接着详细解析音频预处理转换、Vosk模型初始化及识别过程的核心代码,提供多线程优化建议和实时识别扩展思路。文章包含80%以上代码注释,从常见问题排查到性能优化技巧,完整覆盖从"Hello World"到工业级部署的关键技术点,特别适合需要开发本地化语音识别应用的C#开发者。

墨夶的博客 730

Es6Promise的使用

Promise相关的东西

qq_59076775的博客 1899

promise理解应用

promise理解应用 什么是promise 一种处理异步编程的解决方案,本质是对象或者构造函数,内部存放在未来某个事件执行结束的结果。 避免异步回调层层嵌套 js是单线程执行任务,一次执行一个任务,为解决此问题,js将任务执行模式分开为两种,异步和同步。 处理异步执行的任务通过回调方式进行处理 举个例子 一级分类的集合数组里面对应的每项item下还有 二级分类集合数据 异步请求一级分类获取 每项 再通过每项ID 请求二级分类集合 这样形成了异步请求层层嵌套 fetch(initOr..

Mr_Renhappy的博客 592

vue中的.then()与.catch()

catch中获取到的值是请求失败或者代码问题造成的错误,而因代码造成的错误在.then()中获取不到,因此我们常用catch我们偶尔会遇到一些问题:明明请求成功了,逻辑却进入catch中了,这时说明在then中的处理逻辑可能出现了错误,并不是请求失败才会进入catch。

MyHappinessIsU的博客 2万+

ES6之 三异步函数

async异步函数 async函数是使用async关键字声明的函数。 async函数是AsyncFunction构造函数的实例, 并且其中允许使用await关键字。async和await关键字让我们可以用一种更简洁的方式写出基于Promise的异步行为,而无需刻意地链式调用promise

m0_48041877的博客 891

ES6 常用代码

一、组件完成后调用 this.$nextTick(() => ( )) refresh() { this.reload = false this.$nextTick(() => (this.reload = true)) } 二、同步 async getLoadData(data) { let _this = this // 字典 ...

爱兰河少 794

JavaScript手写Promise

面试中经常会被问到你会手写Promise吗?本文带你手撸Promsie

编码世界 5464

手写Promise

若要使缺乏完整 promise 实现的浏览器符合规范,或将 promise 添加到其他浏览器和 Node.js 中,请查看。​ 上面提到的库,以及ES6中实现的Promise,还有我们手写Promise其实都是按照标准进行编写的,那么如何测试是否符合标准呢。无论是早期实现了Promise的第三方库,以及现在的新式浏览器内置的Promise,都是符合。手写Promise-链式编程-fulfilled状态-返回Promise。是社区推出的规范,最早Promise也是社区推出并实现的,旨在规范。

weixin_42782004的博客 1221

手写Promise的基本实现 (超详细)

手写Promise的基本实现 (超详细) 面试必备! 本文带大家实现一个基本的 promise 过多的边界情况就不在考虐,理解主要实现过程以及逻辑即可 对于一个个出现的问题我会逐步分析原因以及对应的解决思路

qq_48554377的博客 8706

什么是 Promise?它解决了什么问题?请手写一个简单的 Promise

Promise一个对象,它代表了一个尚未完成但最终会完成(或失败)的异步操作的结果值。从本质上讲,Promise一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。为了深入理解 Promise 的工作原理,最好的方式莫过于亲手实现一个。通过这种方式,Promise 将回调的“嵌套”关系转变成了 Promise 链的“串联”关系,代码结构更清晰,更符合人类的线性思维习惯。Promise 通过引入链式调用的机制,将深层嵌套的结构“拉平”,转换成一个线性的、自上而下的代码流。

破损的天堂鸟博客 1096

Promise基本使用以及手写源码

Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。所谓Promise,简单说就是一个容器,等Promise执行完,才会执行里面的东西,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。Promise有以下两个特点。

m0_74079648的博客 1731

Promise学习-手写一个promise

学习了Promise的A+规范,以及手写一个Promise后,我对Promise学到的结果。 平常也有用到过promise来处理异步,先回顾下promise的用法 const myPromise = new Promise((resolve,reject) => { //写一些异步操作,比如ajax请求 if(window.onError){ reject('页面加载失败'); } setTimeout(() => { resolve('异步返回结果'); }, 1000)

水蓝针织 1807

then的双回调

then的双回调 在新项目里then的第一个回调中失败请求处理不能拿到服务器返回的错误提示 原写法,部分失败请求返回的信息不能适用 .then(res => { if (res.data.code == 200) { //请求成功处理 this.$emit("updateSucc"); this.initData(); } else { //请求失败处理

kis_wuyan的博客 1796

高频前端面试题汇总之代码输出结果篇---笔记

高频前端面试题汇总之代码输出结果篇---笔记

weixin_43916101的博客 702

(基础)Promisethen()方法使用,多次调用、链式调用

Promise可以被多次调用then方法,链式调用

次顶级的博客 1万+

有关then的“链式调用”

let str1 = 'str1 '; const func1=(str1)=>new Promise((resolve,reject)=>{ resolve(str1 + 'str2 '); }) const func2=(str2)=>new Promise((resolve,reject)=>{ resolve(str2 + 'str3 '); }) const func3=(str3)=>new Promise((resolve,reject...

qq_35306736的博客 7669

axios框架使用

axios基本语法 axios语法 : axios .get('url') .then( res=>{ //请求成功 res.data 服务器响应数据 } ) .catch( err=>{ //请求失败 err"错误信息} ) .then( ()=>{ //本次请求完成 无论成功和失败都会执行 } ) ...

weixin_68531033的博客 1414

ES6(Generator、async、Promise

Generator 是ES6提供的一种异步编程解决方案,语法不同于普通函数;简单的把Generator 理解为一个状态机,封装了多个内部状态,一个yield就是一个状态。执行Generator 函数会返回一个迭代器对象,可以通过调用迭代器next依次遍历Generator函数内部的每一个状态。 Generator函数的两个特征 1、function关键字与函数名之间有个星号 function* helloWorldGenerator(){ 几行代码 yield ...

qq_48108860的博客 332

kinit-Typescript资源

FastAPI + vue3 PCPC Vue3+Typescript+Vite+Element PlusUni-APP + uview uiFastAPI+Pydantic+SQLAlchemy 2.0+MysqlRBAC

上一篇: 对DOM元素进行操作
下一篇: JS数组常用方法整理(14种常用方法)
Zack Not In Amoy
博客等级 码龄5年 68粉丝 14原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值