手写Promise(原生Promise剖析一)

在手写Promise之前,我们需要了解一下什么是Promise,为什么要引入Promise。

1.Promise是ES6引入的一种解决异步编程的方案。

2.为什么要引入Promise呢?可以从问题的根源出手,在我们写一些嵌套的回调函数时会发现,最基本的问题就是回调地狱的产生,同时伴随着当我们不去手动处理回调结果和异常时,我们就很头疼,没办法直接捕获到结果和异常,这时候,Promise就诞生了,他就相当于一个助手,当你将你所需要的回调让他去处理时,他会根据你说提供的回调返回给你一个“正确”、“错误”或者“异常”的结果,同样,也能有效的解决回调地狱的现象(当然是需要配合关键字使用)

到这,你可能还是不明白Promise到底是什么,那么还是从需求入手吧

需求: 第一秒内读取第一个文件,第二秒内读取第二个文件,第三秒内读取第三个文件。

传统的写法如下:

const fs = require('fs')
setTimeout(() => {
    fs.readFile("./文件一.html", (err, data1) => {
        console.log(data1.toString())
    })
    setTimeout(() => {
        fs.readFile("./文件二.html", (err, data2) => {
            console.log(data2)
        })
        setTimeout(() => {
            fs.readFile("./文件三.html", (err, data3) => {
                console.log(data3)
            })
        }, 3000);
    }, 2000);
}, 1000)

很明显,当所读取的文件增加到几百个甚至上千个的时候,代码右边的长度就会无线延伸下去

然后,看看Promise的效果

// 创建一个Promise 
let p = new Promise((resolve, reject) => {
    resolve("Ok")
})

p.then(value => {
    setTimeout(() => {
        fs.readFile("文件一.html", (err, data) => {
            console.log(data)
        })
    }, 2000);
}, reason => {

}).then(value => {
    setTimeout(() => {
        fs.readFile("文件二.html", (err, data) => {
            console.log(data)
        })
    }, 3000);
}, reason => {

}).then(value => {
    setTimeout(() => {
        fs.readFile("文件三.html", (err, data) => {
            console.log(data)
        })
    }, 1000);
}, reason => {

})

显然,回调地狱的问题就解决了,当然,这还不是Promise的全貌,只是Promise许多用法的其中一种,这里也就不一一举出了

回归主题,手写Promise,当然实际开发中,并不会自己手写这个库,但是手写能够很大程度上的帮助我们理解Promise的基本原理和用法。

// 下面针对有一定Promise基础的学者

1.首先,Promise对象中,有最基本的两个属性,PromiseState(状态属性)、PromiseResult(结果属性,默认值为null),状态属性有三种情况“pending”、“fulfilled / resolved”、“rejected”,分别是基础状态(Promise创建之初的状态)、成功状态(调用resolve()函数之后改变成的状态,并执行成功回调)、失败状态(调用reject()函数之后改变成的状态,并执行失败回调 / 或者抛出异常之后调用reject()函数本质是调用函数改变状态)),通过这些内容,我们就可以构建最基本的Promise的雏形:

function Promise(excutor) {
    // 状态属性 、 结果属性
    this.PromiseState = "pending"
    this.PromiseResult = null

    // 内部 resolve函数
    function resolve(data) {

    }

    // 内部 reject函数
    function reject(data) {

    }
}

接下来就要处理resolve、reject这两个函数了,调用这两个函数时需要改变Promise的状态和Promise的结果,并且,值得注意的是,Promise的状态一旦改变状态,就不能再次调用这两个函数改变状态,则,得到以下的Promise:

function Promise(excutor) {
    // 状态属性 、 结果属性
    this.PromiseState = "pending"
    this.PromiseResult = null
    // 保存实例对象的 this
    const _this = this
    // 内部 resolve函数
    function resolve(data) {
        // 判断状态是否已经改变
        if (_this.PromiseState !== "pending") return
        _this.PromiseState = "fulfilled"
        _this.PromiseResult = data
    }

    // 内部 reject函数
    function reject(data) {
        // 判断状态是否已经改变
        if (_this.PromiseState !== "pending") return
        _this.PromiseState = "rejected"
        _this.PromiseResult = data
    }
}

这时候我们需要想到一种情况,那就是前面提到的抛出异常的情况,而什么时候会抛出异常呢,显然,在程序执行的过程中,随时会抛出异常,也就是说,在Promise对象中的任何地方都有可能抛出异常,那么我们就需要,通过try...catch去捕获异常,最简单的方法就是将这Promise整个包裹起来去捕获,这样显得很累赘,太杂糅,我们可以同步的调用执行器函数,也就是“备份”,就是的再另一个地方同步重新跑一遍,以便捕获异常,这也就得到了最基本的Promise:

function Promise(excutor) {
    // 状态属性 、 结果属性
    this.PromiseState = "pending"
    this.PromiseResult = null
    // 保存实例对象的 this
    const _this = this
    // 内部 resolve函数
    function resolve(data) {
        // 判断状态是否已经改变
        if (_this.PromiseState !== "pending") return
        _this.PromiseState = "fulfilled"
        _this.PromiseResult = data
    }

    // 内部 reject函数
    function reject(data) {
        // 判断状态是否已经改变
        if (_this.PromiseState !== "pending") return
        _this.PromiseState = "rejected"
        _this.PromiseResult = data
    }

    // 同步捕获异常
    try {
        // 同步调用 【执行器函数】
        excutor(resolve, reject)
    } catch (e) {
        reject(e)
    }
}

接下来会有相关文章持续更新之后的Promise的优化和相关的 then() 、all() 等函数的封装

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

青灯夜游/

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值