美文网首页
ES6 Promise、手撸一个简单 Promise 实现

ES6 Promise、手撸一个简单 Promise 实现

作者: 行走的蛋白质 | 来源:发表于2019-07-14 19:20 被阅读0次
    • Promise 的特点是什么,优缺点有什么,什么是 Promise 链?
    Promise 是什么
    • 抽象表达:
      • Promise 是 JS 中进行异步编程的新的解决方案
    • 具体表达:
      • 从语法上来说 Promise 是一个构造函数
      • 从功能上来说 Promise 对象用来封装一个异步操作并可以获取其结果
    • 优势:
      • 指定回调函数的方式更加灵活:可以在异步任务完成之后在指定
      • 支持链式调用:回调地狱的问题是不便于阅读以及不便于异常处理
    Promise 的三种状态
    • 等待中(pending)
    • 完成了 (resolved)
    • 拒绝了(rejected)

    当我们在构造 Promise 的时候,构造函数内部的代码是立即执行的

    new Promise((resolve, reject) => {
      console.log('new Promise')
      resolve('success')
    })
    console.log('finifsh')
    // new Promise -> finifsh
    
    Promise 解决 ajax 请求的嵌套和回调地狱问题。

    本次学习用到了支持 Promise API 的 axios 包 它可以帮助我们通过发起 ajax 请求拿到 Promise 数据。

        <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
        <script>
            let userName    
            const usersPromise = axios.get('https://api.github.com/users');
            // 这里的 .then 方法可以简单理解为事件监听
            usersPromise.then(res => {
                console.log(res);
                userName = res.data[0].login;
                return axios.get(`https://api.github.com/users/${userName}/repos`);
            }).then(res => {
                console.log(res);
            }).catch(err => { // 捕获错误
                console.error(err);
            })
        </script>
    
    Promise 链式调用
            const protein1 = new Promise((resolve, reject) => {
                if(/*condition1*/) {
                    resolve(res);
                } else {
                    reject(Error('error1'));
                }
            })
    
            function protein2(value) {
                return new Promise((resolve, reject) => {
                    if(/*condition2*/) {
                        resolve(res);
                    } else {
                        reject(Error('error2'));
                    }
                })
            }
    
            protein1.then(res => {
                // 还可以调用返回 Promise 的函数后续继续进行 .then 的链式调用
            }).then(res => {
    
            }).catch(err => {
                
            })
    
    多个 Promise 且之间没有关联
            const protein1 = new Promise((resolve, reject) => {
                if(/*condition1*/) {
                    resolve(res);
                } else {
                    reject(Error('error1'));
                }
            })
    
            const protein2 new Promise((resolve, reject) => {
                if(/*condition2*/) {
                    resolve(res);
                } else {
                    reject(Error('error2'));
                }
            })
    
            Promise.all([protein1, protein2])
                .then(res => {
                    // 这里的 res 是 protein1 protein2 的返回值并将其放到数组里面我们可以用数组的解构方法将其取出来
                    const [protein1res, protein2res] = res;
                }).catch(err => {
                    
                })
    

    Promise.all() 方法会等到所有 Promise 都出结果,返回给我们 res 或者有其中一个出错误就返回 err 在 catch 里面捕获到。
    与之对应 Promise.race() 方法是由第一个返回结果而定,如果返回值那么 res 如果出错误那么捕获 err。

    Promise 的缺点

    无法取消 Promise,错误需要通过回调函数捕获

    实现一个简易版 Promise
    // 首先搭建大体框架
    const PENDING = 'pending'
    const RESOLVED = 'resolved'
    const REJECTED = 'rejected'
    
    function SimplePromise(fun) {
        const _this = this
    
        _this.state = PENDING
        _this.value = null
        _this.resolvedCallbacks = []
        _this.rejectedCallbacks = []
        // 待完善 resolve 和 reject 函数
        // 待完善执行 fun 函数
    }
    
    • 首先创建三个常量表示状态,对于经常用到的创建常量便于开发以及后期维护
    • 由于代码可能会异步执行,创建常量 _this 用于获取正确的 this 对象
    • Promise 的初始状态是 pending
    • value 用于保存 resolve 或者 reject 中传入的值
    • resolvedCallbacks 和 rejectedCallbacks 用于保存 then 中的回调,因为当执行完 Promise 的时候状态可能还在 pending 中,这时候应该把 then 中的回调保存起来用于状态改变的时候使用
    // 接下来我们完善 resolve 和 reject 函数,添加哎 SimplePromise 函数内部
    function resolve(value) {
        if(_this.state === PENDING) {
            _this.state = RESOLVED
            _this.value = value
            _this.resolvedCallbacks.map(cb => cb(_this.value))
        }
    }
    function reject(value) {
        if(_this.state === PENDING) {
            _this.state = REJECTED
            _this.value = value
            _this.rejectedCallbacks.map(cb => cb(_this.value))
        }
    }
    
    • 判断当前状态是不是等待中,因为规范规定只有等待中可以改变状态
    • 将当前状态更改为对应状态,并将传入的值赋给 value
    • 遍历回调函数并执行
    // 然后实现如何执行 Promise 中传入的函数
    try {
        fun(resolve, reject) 
    } catch (e) {
        reject(e)
    }
    
    • 执行传入的参数并将之前两个函数当作参数传进去
    • 执行函数过程中会遇到错误,需要捕获错误并执行 reject 函数
    // 最后实现较为复杂的 then 函数
    SimplePromise.prototype.then = function (onFullfilled, onRejected) {
        const _this = this
        onFullfilled = typeof onFullfilled === 'function' ? onFullfilled : v => v
        onRejected = 
            typeof onRejected === 'function' 
            ? onRejected
            : r => {
                throw r
            }
        if(_this.state === PENDING) {
            _this.resolvedCallbacks.push(onFullfilled)
            _this.rejectedCallbacks.push(onRejected)
        }
        if(_this.state === RESOLVED) {
            onFullfilled(_this.value)
        }
        if(_this.state === REJECTED) {
            onRejected(_this.value)
        }
    }
    
    • 首先判断两个参数是不是函数类型,因为两个参数不必传
    • 当参数不是函数类型时,创建一个函数赋值给对应参数
    • 最后是判断状态的逻辑,pending 状态往回调函数中 push 函数,不是 pending 执行对应函数

    简单 Promise 完全体加用法实现如下代码示例:
    复杂完整实现请戳这里。。。

    // 首先搭建大体框架
    const PENDING = 'pending'
    const RESOLVED = 'resolved'
    const REJECTED = 'rejected'
    
    function SimplePromise(fun) {
        const _this = this
    
        _this.state = PENDING
        _this.value = null
        _this.resolvedCallbacks = []
        _this.rejectedCallbacks = []
        // 待完善 resolve 和 reject 函数
        // 待完善执行 fun 函数
    
        // 接下来我们完善 resolve 和 reject 函数,添加哎 SimplePromise 函数内部
        function resolve(value) {
            if(_this.state === PENDING) {
                _this.state = RESOLVED
                _this.value = value
                _this.resolvedCallbacks.map(cb => cb(_this.value))
            }
        }
        function reject(value) {
            if(_this.state === PENDING) {
                _this.state = REJECTED
                _this.value = value
                _this.rejectedCallbacks.map(cb => cb(_this.value))
            }
        }
    
        // 然后实现如何执行 Promise 中传入的函数
        try {
            fun(resolve, reject) 
        } catch (e) {
            reject(e)
        }
    }
    
    // 最后实现较为复杂的 then 函数
    SimplePromise.prototype.then = function (onFullfilled, onRejected) {
        const _this = this
        onFullfilled = typeof onFullfilled === 'function' ? onFullfilled : v => v
        onRejected = 
            typeof onRejected === 'function' 
            ? onRejected
            : r => {
                throw r
            }
        if(_this.state === PENDING) {
            _this.resolvedCallbacks.push(onFullfilled)
            _this.rejectedCallbacks.push(onRejected)
        }
        if(_this.state === RESOLVED) {
            onFullfilled(_this.value)
        }
        if(_this.state === REJECTED) {
            onRejected(_this.value)
        }
    }
    
    // 用法
    var newPromise = new SimplePromise((resolve, reject) => {
        setTimeout(() => {
            resolve('success')
        }, 0)
    }).then(v => {
        console.log(v)
    })
    

    相关文章

      网友评论

          本文标题:ES6 Promise、手撸一个简单 Promise 实现

          本文链接:https://www.haomeiwen.com/subject/sxabkctx.html