前端学习指南饥人谷技术博客让前端飞

JS中的几种异步编程方式以及promise基本功能的实现

2017-07-09  本文已影响658人  大春春

参考文献

Javascript异步编程的4种方法
阮一峰ES6教程---Promise

相关技术

Promis, class, 面向对象

JS中的同步和异步

// 任务一
        function fn1() {
            console.log(3)
            setTimeout(function() {
                console.log(1)
            }, 0)
        }
// 任务二
        function fn2() {
            console.log(2)
        }
        fn1()
        fn2()

在该例子中,setTimeout函数是异步的,在任务一执行过程中遇到了setTimeout,于是将其内的任务操作放到了事件队列的队尾,先去执行任务二,执行完毕后再回过头来执行队尾的任务console.log(1),在此过程中,任务一内的执行没有阻塞任务二的执行

输出结果


几种异步任务模式

        function fn(callback1, callback2) {
            // 耗时操作
            let a = 0
            for (let i = 0; i < 100; i++) {
                a++
            }
            setTimeout(function() {
                callback1(++a)
                setTimeout(function() {
                    callback2(++a)
                }, 0)
            }, 0)
        }

        function fn1(a) {
            console.log(a)
        }

        function fn2(a) {
            console.log(a)
        }
        fn(fn1, fn2)
        class EventCenter {
            // 定义事件中心
            constructor() {
                this.events = {}
            }

            // 发布器
            on(evt, handler) {
                // 检测事件信号是否存在,当存在时不做操作,不存在时创建给予这个信号的方法存储器(数组)
                this.events[evt] = this.events[evt] || []
                    // 将传入的方法放入数组中
                this.events[evt].push({
                    handler: handler
                })
            }

            // 订阅器
            fire(evt, params) {
                // 检测当前被订阅的信号是否存在,存在则执行其内的所有方法
                if (!this.events[evt]) {
                    return
                }
                for (let i = 0; i < this.events[evt].length; i++) {
                    this.events[evt][i].handler(params)
                }
            }
        }

        let center = new EventCenter()

        center.on('event', function(data) {
            console.log('event执行了第一个任务')
        })

        center.on('event', function(data) {
            console.log('event执行了第二个任务')
        })

        center.fire('event')

输出结果:


        function getData(){
            let promise = new Promise((resolve, reject) => {
                //  AJAX获取数据。。。。
                if(success){
                    // 成功时执行
                    resolve(fn1)
                }else{
                    // 失败时执行
                    reject(fn2)
                }
            })

            return promise
        }

        getData().then(fn1).catch(fn2)

可以从中发现,除了thencatch两个方法外,Promise还有链式调用的功能,那么下面就实现这样的一个Promise。

Promise基本功能的实现

        let p = new Promise()

        function f1() {
            console.log('f1')
            setTimeout(function() {
                p.resolve('1')
            }, 1000)
            return p
        }

        function f2(result) {
            console.log('f2', result)
            setTimeout(function() {
                p.resolve('2')
            }, 1000)
        }

        function f3(result) {
            console.log('f3', result)
            setTimeout(function() {
                p.resolve('3')
            }, 1000)
        }

        function f4(result) {
            console.log('f4', result)
        }

        f1().then(f2).then(f3).catch(f4)
// 或者 f1().then(f2, f4).then(f3, f4)
        class promise {
            constructor(){

            }

            then(success, fail) {
                // 链式调用
                return this
            }

            catch (fail) {
                // 链式调用
                return this
            }
        }
        class promise {
            constructor() {

            }

            then(success, fail) {
                // 链式调用
                return this
            }

            catch (fail) {
                // 链式调用
                return this
            }

            // 成功状态的管理
            resolve(result) {

            }

            // 失败状态的管理
            reject(result) {

            }
        }
        class promise {
            constructor() {
                this.callbacks = []
            }

            then(success, fail) {
                // 链式调用
                return this
            }

            catch (fail) {
                // 链式调用
                return this
            }

            // 成功状态的管理
            resolve(result) {
                this.actuator('resolve', result)
            }

            // 失败状态的管理
            reject(result) {
                this.actuator('reject', result)
            }

            // 执行器
            actuator(status, result) {
                
            }
        }
// 为了方便查看放到了最上面
        let p = new promise()
        function f1() {
            console.log('f1')
            setTimeout(function() {
                p.resolve('1')
            }, 1000)
            return p
        }
// ①、在写then函数之前,先看看最开始Promise的调用方式是怎么样的:f1().then(f2).then(f3).catch(f4),
然后在f1中嵌套回调f2并且返回这个Promise对象。
此外,then函数可以接受两个参数,一个成功回调一个失败回调,
所以思路就是创建一个对象里面有'resolve'和'reject'对应这两个回调然后放入callbacks数组中进行管理;
            then(success, fail) {
                this.callbacks.push({
                    resolve: success,
                    reject: fail
                })
                // 链式调用
                return this
            }


// ②、这时候在调用f1时他会先返回Promise对象,然后再调用setTimeout里面的resolve回调并传入参数,而在resolve函数中调用了执行器actuator,并且传入了resolve这个状态和在f1中传入的参数;
            // 成功状态的管理
            resolve(result) {
                this.actuator('resolve', result)
            }

// ③、执行actuator函数,其实分析到了这一步就很简单了,不过是将先前传入callbaks中的函数取出来,然后执行其中的成功回调就是了
            actuator(status, result) {
                // 取出之前传入的回调函数对象(包含成功和失败回调),然后执行
                let handlerObj = this.callbacks.shift()
                handlerObj[type](result)
            }

// ④、整体代码

        class promise {
            constructor() {
                this.callbacks = []
            }

            then(success, fail) {
                this.callbacks.push({
                    resolve: success,
                    reject: fail
                })
                // 链式调用
                return this
            }

            catch (fail) {
                // 链式调用
                return this
            }

            // 成功状态的管理
            resolve(result) {
                this.actuator('resolve', result)
            }

            // 失败状态的管理
            reject(result) {
                this.actuator('reject', result)
            }

            // 执行器
            actuator(status, result) {
                // 取出之前传入的回调函数对象(包含成功和失败回调),然后执行
                let handlerObj = this.callbacks.shift()
                handlerObj[status](result)
            }
        }

其实到了这一步,Promise的基本功能(resolve和reject)已经实现了,下面来看看f1().then(f2, f4).then(f3, f4).then(f4)的执行结果吧
①、全部resolve状态执行结果


②、f2为reject时候执行结果
        function f2(result) {
            console.log('f2', result)
            setTimeout(function() {
                p.reject('2')
            }, 1000)
        }
        class promise {
            constructor() {
                    // 定义回调函数管理器和catch
                    this.callbacks = []
                    this.oncatch
                }
                // 当状态为reject时候,传入reject状态给执行器
            reject(result) {
                    this.actuator('reject', result)
                }
                // 当状态为resolve时候,传入resolve状态给执行器
            resolve(result) {
                    this.actuator('resolve', result)
                }
                // 执行器
            actuator(status, result) {
                // 检测当状态为reject并且oncatch不为空时,执行oncatch保存的失败回调, 适用于f1().then(f2).then(f3).catch(f4)
                if (status === 'reject' && this.catch) {
                    this.callbacks = []
                    this.oncatch(result)
                // 检测当callbacks第一位有方法时,执行相应状态的方法,适用于f1().then(f2, f4).then(f3, f4)
                } else if (this.callbacks[0]) {
                    let handlerObj = this.callbacks.shift()
                    if (handlerObj[status]) {
                        handlerObj[status](result)
                    }
                }
            }

            then(success, fail) {
                // 将传入的成功和失败回调组成对象,放入回调数组中进行管理
                this.callbacks.push({
                    resolve: success,
                    reject: fail
                })
                // 用于链式调用
                return this
            }

            catch (fail) {
                // 保存传入的失败回调
                this.oncatch = fail
                // 用于链式调用
                return this
            }
        }


        let p = new promise()

        function f1() {
            console.log('f1')
            setTimeout(function() {
                p.resolve('1')
            }, 1000)
            return p
        }

        function f2(result) {
            console.log('f2', result)
            setTimeout(function() {
                p.resolve('2')
            }, 1000)
        }

        function f3(result) {
            console.log('f3', result)
            setTimeout(function() {
                p.resolve('3')
            }, 1000)
        }

        function f4(result) {
            console.log('f4', result)
        }
        // 第一种调用
        f1().then(f2).then(f3).catch(f4)
        // 第二种调用
        f1().then(f2, f4).then(f3, f4)

附录,ES7中新增了await async关键字用于实现更简单更直观的异步代码,甚至写出来后和同步执行的代码看起来没什么区别,但在本质上还是使用了Promise,想要了解的同学也可以点击下面的链接一起学习,在此就不再多做介绍了.

体验异步的终极解决方案-ES7的Async/Await

上一篇 下一篇

猜你喜欢

热点阅读