首页 > 编程语言 >Promise手动实现和Async Await拓展(JavaScript)

Promise手动实现和Async Await拓展(JavaScript)

时间:2022-11-30 13:56:20浏览次数:38  
标签:resolve PromiseResult Await MyPromise PromiseState Promise reject Async 回调

Promise手动实现

咱们来看一段Promise的代码:


let p1 = new Promise((resolve, reject) => {
    resolve('成功')
    reject('失败')![]()
})
console.log('p1', p1)

let p2 = new Promise((resolve, reject) => {
    reject('失败')
    resolve('成功')
})
console.log('p2', p2)

let p3 = new Promise((resolve, reject) => {
    throw('报错')
})
console.log('p3', p3)

输出结果

p1 Promise {: “成功”}
p2 Promise {: “失败”}
p3 Promise {: “报错”}

resolve和reject的实现

所以可以得出以下几个知识点
1.说明如果当resolve调用或者reject调用过后,就不会执行后面的代码了
2.如果在Promise的回调里面抛出错误的时候一共是执行reject的代码然后就停止继续往后执行了
3.Promise里面有对应的状态信息和状态返回结果( fulfilled 成功)(rejected 失败)

emm…那么首先上代码吧


class MyPromise {
    // 构造方法
    constructor(executor) {

        this.init(); //首先进行一个类的初始化
        // 执行传进来的函数
        executor(this.resolve, this.reject)
    }
   init(){
   this.initValue();
   this.initBind();
   }
    initBind() {
         // 初始化值
        this.initValue()
        // 初始化this指向
        this.initBind()
    }

    initValue() {
        this.resolve = this.resolve.bind(this)
        this.reject = this.reject.bind(this) // 绑定当前的类的this
    }

    resolve(value) {
        // 如果执行resolve,状态变为fulfilled
        this.PromiseState = 'fulfilled'
        // 终值为传进来的值
        this.PromiseResult = value
    }

    reject(reason) {
        // 如果执行reject,状态变为rejected
        this.PromiseState = 'rejected'
        // 终值为传进来的reason
        this.PromiseResult = reason
    }
}

那么首先解释下:

首先自定义一个类MyPromise然后在类的初始化构造函数里面自定义了一个自己的init方法
这个方法那么执行的事情有两件
1.1 定义一个绑定当前类的最终Promise的值PromiseResult 最终的Promise的状态PromiseState
1.2 定义让resolve和reject的this的指向永远指向当前的类,而不是随着用户的嵌套而丢失自己
那么我们试试看


const test1 = new MyPromise((resolve, reject) => {
    resolve('成功')
})
console.log(test1) // MyPromise { PromiseState: 'fulfilled', PromiseResult: '成功' }

const test2 = new MyPromise((resolve, reject) => {
    reject('失败')
})
console.log(test2) // MyPromise { PromiseState: 'rejected', PromiseResult: '失败' }

但是并没有彻底解决,只是第一步,接下来我们要处理的的是

执行对应回调和解决报错

1.如果resolve或者reject调用过后那么就执行对应的回调
2.如果抛出错误那么就执行对应的reject代码
先上代码


class MyPromise {
    // 构造方法
    constructor(executor) {

        this.init();

        try{executor(this.resolve, this.reject)}catch(e){this.reject(e.message)}
    }
    init(){
        // 初始化值
        this.initValue()
        // 初始化this指向
        this.initBind()
        // 执行传进来的函数
    }
    initBind() {
        this.resolve = this.resolve.bind(this);
        this.reject = this.reject.bind(this);
    }

    initValue() {
        this.PromiseResult = null ;
        this.PromiseState = 'pending';
    }

    resolve(value) {
        this.PromiseState === "pending"   && (()=>{
             this.PromiseState = 'fulfilled';
             this.PromiseResult = value;
        })();
    }

    reject(reason) {
        this.PromiseState === "pending" && (()=>{
            console.log("reject");
            this.PromiseState = 'rejected'
            this.PromiseResult = reason
        })();
    }
}

OK,如你所见,在运行之前还是先讲下做了些什么东西
1.在原基础上的reject和resolve的上面做了判断,判断当前的PromiseState的状态为pending的状态下然后再去调用一个匿名的箭头回调函数(相信很多大佬知道意思,但是为了部分小白这里的话还是再详细说明下这样写的意思,为什么用匿名函数?因为这个地方的逻辑与操作符只能跟着你要做的调用操作而不是赋值,为什么要用箭头回调,里面的this指向没有问题?因为箭头函数在ES6中有明确介绍(这个地方建议小白自己去看下手册详细解释))
2.在调用传进来的方法的时候进行了一个try{…}catch(e){…}的包含操作用于包含异常的行为然后做出调用this.reject的操作

那么这里我们试试运行的结果


const result = new MyPromise((resolve,reject)=>{throw Error("god")});
console.log(result);
// MyPromise {PromiseResult: "god", PromiseState: "rejected", resolve: ƒ, reject: ƒ}

OK,但是作者觉得为了便于观看和后期维护,如下我做了一点小改变


class MyPromise {
    constructor(executor) {
        this.PromiseResult = null ?? (()=>this.PromiseState = 'pending')();
        const {resolve,reject} = this.methods = {
            resolve:((result)=>this.main(result,"fulfilled")).bind(this),
            reject:((result)=>this.main(result,"rejected")).bind(this),
        }
        try{executor(resolve,reject)}catch(e){reject(e.message)}
    }

    main(value,stateName) {
        this.PromiseState === "pending"   && (()=>{
             this.PromiseState = stateName;this.PromiseResult = value;
        })();
    }
}

改变解析:
1.提出一个综合的resolve和reject的处理函数
2.集中吧resolve 、reject放在methods的对象里面
3.进行了判断PromiseResult的初始化为null

到目前为止我们的MyPromise的写法已经差不多完善了,
但是目前为止我们的MyPromise是不是少了一个东西呢?
没错就是then方法
为了省时间我这里就直接先说在常规的Promise的状态下then的用处点

then的实现

1.then接收两个回调,一个是成功回调,一个是失败回调
2.当Promise状态为fulfilled执行成功回调,为rejected执行失败回调
3.如resolve或reject在定时器里,则定时器结束后再执行then
4.then支持链式调用,下一次then执行受上一次then返回值的影响

先上代码


class MyPromise {

    constructor(executor) {

        this.PromiseResult = null ?? (()=>this.PromiseState = 'pending')();
        const {resolve,reject} = this.methods = {
            resolve:((result)=>this.main(result,"fulfilled")).bind(this),
            reject:((result)=>this.main(result,"rejected")).bind(this),
        }
        try{executor(resolve,reject)}catch(e){reject(e.message)}
    }

    main(value,stateName) {
        this.PromiseState === "pending"   && (()=>{
             this.PromiseState = stateName;this.PromiseResult = value;
        })();
    }
    then(onFulfilled, onRejected) {
        // 接收两个回调 onFulfilled, onRejected

        // 参数校验,确保一定是函数
        if(typeof onFulfilled !== 'function') throw Error("onFulfilled is not function");
        if(typeof onRejected !== 'function')  throw Error("onRejected is not function");

       (this.PromiseState === 'fulfilled') &&  onFulfilled(this.PromiseResult); // 如果当前为成功状态,执行第一个回调
       (this.PromiseState === 'rejected') && onRejected(this.PromiseResult); // 如果当前为失败状态,执行第二哥回调

        }

    }

首先解释:
1.写then方法接收两个回调方法,第一个是成功的回调,第二个是失败的回调
2.then方法首先需要检查传进来的是否是回调方法不是就报错
3.然后再then方法里面再判断当前的PromiseState的最终状态
,然后进行调用回调函数传参

OK,看看输出效果


首先解释:
1.写then方法接收两个回调方法,第一个是成功的回调,第二个是失败的回调
2.then方法首先需要检查传进来的是否是回调方法不是就报错
3.然后再then方法里面再判断当前的PromiseState的最终状态
,然后进行调用回调函数传参

OK,看看输出效果

可以看出基本是已经实现了大部分的Promise的使用,那么这里的话就说下如果遇到定时任务或者需要花费很多时间但需要同步的任务如何处理

首先梳理下,用户是调用MyPromise然后传进需要操作的函数,然后如果要在MyPromise里面要返回参数那么就会调用resolve或者reject的方法,那么这里的话最重要的就是说不管用户传进来啥参数,最后肯定是会调用resolve或者reject来执行返回参数,所以说如果在的setTimeout函数执行resolve或者reject,我们并不是说需要计算这个函数是要等它过了多少秒,而是说我们是要让resolve被调用过后,然后再去执行then里面的方法,下面再简单的梳理下

执行步骤解析

new MyPromise((resolve,rejct)=>…(耗时需要同步的操作)…).then(res=>…(如果上面的操作完毕了就执行这个地方))—>进行初始化处理,初始化完毕过后首先会调用then方法(首先你不要按照你自己的思路来说一定要等待new MyPromise的里面操作完毕才执行then),—>then接收到了成功和失败的回调,因为现在是不能立刻执行then给的回调要 等到resolve或reject,resolve或reject,resolve或reject ! ! ! (重要的事情说三遍),也就是说当执行了resolve或者reject,然后再去触发then里面给的回调—>resolve被执行那么久执行then里面的成功的回调,reject被执行那么就执行then里面的失败的回调

思路就是如上,如果觉得不清楚,就麻烦再仔细看下,然后对比下文代码


class MyPromise {

    constructor(executor) {

        this.PromiseResult = null;
        this.PromiseState = 'Pending';
        this.data = {
            callBacks:{
                    onFulfilledCallbacks :[],
                    onRejectedCallbacks :[],
            }
        }
        const {resolve,reject} = this.methods = {
            resolve:((result)=>this.main(result,"Fulfilled")).bind(this),
            reject:((result)=>this.main(result,"Rejected")).bind(this),
            addCallBack:(onFulfilled,onRejected)=>{
                this.data.callBacks.onFulfilledCallbacks.push(onFulfilled);
                this.data.callBacks.onRejectedCallbacks.push(onRejected);
            }

        }
        try{executor(resolve,reject)}catch(e){reject(e.message)}
    }

    main(value,stateName) {

            this.PromiseState === "Pending"   && (()=>{
            this.PromiseState = stateName;this.PromiseResult = value;
            const callBacks = (this.data.callBacks[`on${stateName}Callbacks`]);

            while(callBacks.length) callBacks.shift()(this.PromiseResult);
                })()
            //上面这段代码的意思就是说如果resolve或者reject过后 我们要调用一个方法然后并且让存储回调的数组删除调用过的方法然后更新

    }
    then(onFulfilled, onRejected) {

        // 接收两个回调 onFulfilled, onRejected

        // 参数校验,确保一定是函数
        if(typeof onFulfilled !== 'function') throw Error("onFulfilled is not function");
        if(typeof onRejected !== 'function')  throw Error("onRejected is not function");

        (this.PromiseState === 'Fulfilled') &&  onFulfilled(this.PromiseResult); // 如果当前为成功状态,执行第一个回调
        (this.PromiseState === 'Rejected') && onRejected(this.PromiseResult); // 如果当前为失败状态,执行第二哥回调

        (this.PromiseState === "Pending") && this.methods.addCallBack(onFulfilled,onRejected); //这个地方就是针对定时器、耗时任务任务来进行处理的
        //因为在没有resolve,reject的情况下PromiseState肯定是pending状态,所以这个地方我们首先把then给的成功的回调和失败的回调进行存储起来
        //一旦resolve 或者  reject 再去调用存储起来的回调

        }

    }

const result = new MyPromise((resolve,reject)=>{
    setTimeout(()=>{
    reject("god") 
    },1500);
    });
result.then(res=>console.log("success",res),err=>console.log('error',err));
// 延迟1.5秒输出errorgod

上面主要在then里面增加了新的判断PromiseState的状态语句然后添加到成功和失败的对应的callBacks中,然后resolve或者reject过后就调用对应的回调

(呼~) 到这里的话大概的Promise的实现就写的差不多啦,写多了怕小伙伴们没看懂 其实就是偷懒 ,作者也是新人作者一枚,有些地方写的不清楚可以在评论区评论,作者会尽量在第一时间给你们回复

Async Await的拓展

相信不少小伙伴也试了在上面我们自己写MyPromise是不是和Async Await搭配起来也能实现同步执行代码呢

MyPromise和await搭配同步


(async ()=>{
    const result = await new MyPromise((resolve,reject)=>{
    setTimeout(()=>{
        resolve("hi")
    },3000)
    });
    console.log(result);
    console.log("bye");
})()
//延迟3秒输出 "hi"
//跟随输出 "bye"

确实是没问题的,那么我们就尝试自己写一个不基于上面Promise的写法写个可同步或者异步的setTimeOut

第一种方案是可以不需要搭配async await配套使用


function syncSetTimeOut(callback,sleep){
        const nowTime = new Date().getTime();
        while(new Date().getTime()- nowTime < sleep)'';
        callback();
}
syncSetTimeOut(()=>console.log("测试"),3000);

下面这种就是需要async await搭配使用


class Wait {
        constructor(executor) {
          this.done = this.done.bind(this);
          this.callBack = null;
          executor(this.done);
        }
        done(){this.callBack();}

        then(callBack) {this.callBack = callBack;}
} 
function syncSetTimeOut(callback,sleepnum){
    return new Wait((done) => {
        setTimeout(() => {
            done(callback());
        }, sleepnum);
    });
     }
(async ()=>{
    console.log("开始延迟3秒");
    const result = await syncSetTimeOut(()=>console.log("hello"),3000);
    console.log("延迟结束");
})()
// 开始延迟3秒
// hello
//延迟结束

标签:resolve,PromiseResult,Await,MyPromise,PromiseState,Promise,reject,Async,回调
From: https://www.cnblogs.com/anhiao/p/16938158.html

相关文章