day19:闭包及promise

闭包     

概述:

函数嵌套函数 内部函数拥有外部函数的引用 对应的外部函数不会被gc回收

作用域

  • 全局作用域(global)

里面的this指向对应的global对象 也就是说对应的全局作用域的变量其实都是global对象的属性

  • 局部作用域(函数作用域)

函数的预编译过程

局部作用域

  1. 创建AO对象 (Activation Object 执行上下文)(开辟的内存空间)(会在堆中开辟一个跟函数名一样名字的空间)
  2. 给函数里面的形参、变量进行赋值操作 (undefined)
  3. 形参和实参同步
  4. 找到函数声明 赋值给函数体
function fn(a=1,b=2){
    console.log(a,b,c) //1,2,undefined
    var c = function(){
        console.log(1)
    }
    console.log(c) //函数
}
fn()

全局作用域(全局暴露 对变量来说有全局污染的问题)

  1. 创建GO对象 (Global Object 全局对象)(给对应的global对象添加属性)
  2. 给函数里面的形参、变量进行赋值操作 (undefined)
  3. 形参和实参同步
  4. 找到函数声明 赋值给函数体
console.log(a) //function
var a = 10
function a(){}
console.log(a) //10 (全局污染)

函数执行过程

  1. 去堆中找到对应的函数名所有对应的地址,放入执行栈中执行(压栈)
  2. 执行过程中(开辟对应的执行空间)使用的对应执行上下文进行执行(函数体)
  3. 返回对应的结果(结果不会销毁)
  4. 执行完(销毁对应的执行空间 以及对应的函数体) (出栈)
function fn(){
    var a = 1
    console.log(++a)
}
function fn1(){
    var b = 2
    console.log(--b)
    return b
}
fn()//压栈 2
fn1()//压栈 1
fn()//压栈 2
fn1()//压栈 1
var a = 20 //没有被回收 因为它是global的属性 (程序没关闭 则不会被回收)
cosole.log(a++) //20
cosole.log(a++) //21

实现一个函数调用一次自增一次

// let i = 0 //不会被销毁
// function fn() {
//     i++ //全局变量
//     console.log(i)
// }
// fn() //1
// fn() //2
// fn() //3
// function fn(){
//     var i = 0 //i每次调用都会被销毁
//     i++
//     console.log(i)
// }
// fn() //1
// fn() //1
// fn() //1
//标记清除 (变量) 引用计数 (对象) 只有保持引用就不会被回收
//可以return内容不会被销毁的特性 返回一个引用给外界使用 那么外界在使用的时候就保持了引用就不会
被回收
// function fn(){
//     var i = 0 //i每次调用都会被销毁
//     i++
//     console.log(i)
//     return {
//         i
//     }
// }
// var obj = fn() //使用obj进行接收 这个时候就将函数的内容返回的对象应用加给对应的变量(全
局)
// console.log(obj.i++)//1
// console.log(obj.i++)//2
// console.log(obj.i++)//3
//也就是说通过上面的形式 我们可以返回一个引用数据类型 让外界保持引用那么这个内容就不会被回收
//那么对应的函数也是一个引用数据类型 (同理)
function fn(){
    var i = 0
    return function(){
        i++ //标记为yes i也不会回收
        console.log(i)
    }
}
//闭包占用内存大 容易造成内存泄漏
var closureFn = fn() //接收一个函数
closureFn()//1
closureFn()//2
closureFn()//3
//解决内存泄漏
fn = null

从上述代码可以得到对应函数中return 一个引用数据类型 在这个引用数据类型内容保持对应的外部的一个参数或者是变量的引用那么这个变量将不会被回收。(扩大了函数内容变量的作用范围)

闭包的优缺点

优点

  • 防止变量的全局污染(变量是局部变量)
  • 扩大变量的作用域
  • 缓存对应的数据

缺点

  • 过度使用会造成内存泄漏(当前空间没有被使用但是没有被销毁)
  • 对应的内存消耗大(性能差) (内部函数时刻保持对应外部函数的变量或参数的引用)

闭包的用途

作为缓存(容量小 速度快)

防抖

节流

函数柯里化(可读性 维护性)

防抖(debounce)

概述

在规定时间内只执行一次(执行最后一次)

代码实现

    <button>点他</button>
    <script>
        function debounce(callback,delay){
            var timer = null
            return function(){
                clearInterval(timer)
                timer = setInterval(()=>{
                    callback()
                    clearInterval(timer)
                },delay)
            }
        }

        var btn = document.querySelector('button')
        var fn = debounce(function(){
            console.log('点击')
        },500)
        // 事件驱动
        btn.onclick = fn
    </script>

节流(throttling)

在规定时间内执行一次 执行完之后再继续执行。(用于减少对应的次数)

代码实现

    <button>点击</button>
    <script>
        function throlling(callback,delay){
            var timer = null //节流阀
            return function(){
                if(!timer){
                    timer = setTimeout(()=>{
                        callback()
                        clearTimeout(timer)
                        timer = null
                    },delay)
                }
            }
        }

        var fn = throlling(()=>{
            console.log('点击了')
        },1000)
        document.querySelector('button').onclick = fn
    </script>

函数柯里化

将一个多个参数的函数 分成多个函数(彼此之间可以任意组合)

示例

//求和的函数
function sum(a,b,c){
    return a+b+c
}
sum(1,2,3)//6
sum(1,2,4)

简单函数柯里化

        function sum(a,b,c){
            return a+b+c
        }
        // sum(1,2,3)
        // 简单柯里化
        // function sum(a){
        //     return function(b){
        //         return function(c){
        //             return a+b+c
        //         }
        //     }
        // }
        // let fn = sum(1)(2)
        // console.log(fn(3))//6
        // console.log(fn(4))//7

高阶函数柯里化

            // 包装 将普通函数变成柯里化函数
            // 当前currying函数可以传入一个函数 还可以传入对应的参数(用于执行)

            function currying(fn){
                // 接收传入的参数 arguments (不包含传入的函数)
                let args = Array.prototype.slice.call(arguments,1)
                return function(){
                    // 接收currying传入的参数和对应的函数的参数数组
                    let allArgs = args.concat([...arguments])
                    // 判断参数是否达到对应的个数
                    if(allArgs.length < fn.length){
                        // 没有达到个数返回对应的函数
                        return currying.apply(this,[fn].concat(allArgs))
                    }else{
                        // 到达个数返回值
                        // 调用传入的函数 将参数传入
                        return fn.apply(this,allArgs)
                    }
                }
            }
            let fn = currying(sum)
            console.log(fn(1))
            console.log(fn(1,2)(3))
            console.log(fn(1,2,3))

函数柯里化的核心

参数没遇到对应的个数返回的是函数 参数到了返回的是值

Promise

概述

promise 是ES6新增的一个类,用于解决异步问题(替代回调函数)

promise的三种状态 状态唯一

  • 等待 pending
  • 成功 fulfilled(有对应的处理)
  • 失败 reject (有对应的处理)

promis的构建

//传入函数来进行构建 传入的函数内有俩个参数传递 (resolve、reject都是函数)
//new Promise是同步执行的代码 它的里面可以包含异步代码
new Promise((resolve,reject)=>{
    console.log('hello') //也是同步的
})

异步代码如何同步执行

使用回调函数

        //回调函数解决的问题
        function fn(message, delay = 0, callback) {
            setTimeout(() => {
                console.log(message)
                callback()
            }, delay)
        }
        //这个代码没有任何问题 但是这个代码的可维护性低 可读性低 (回调地狱)这个代码没有可用性(避免回调函数不能嵌套过深)
        fn('1', 1000, () => {
            fn('2', 500, () => {
                fn('3', 1000, () => {
                    fn('4', 2000, () => {
                        fn('5', 100, () => {
                            fn('6', 1000, () => {
                                // ....
                            })
                        })
                    })
                })
            })
        })

回调函数嵌套过深会导致回调地狱

使用promise解决回调地狱

        //resolve 触发成功的函数 对应的处理的方法 then
        //reject 触发失败的函数 对应的处理的方法 catch
        new Promise((resolve, reject) => {
            setTimeout(() => {
                console.log(1);
                //调用成功的函数
                resolve()
            }, 1000)
        }).then(() => {
            //在then方法里面通过返回对应的新的promise来调用下一个then
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    console.log(2);
                    resolve()
                }, 500)
            })
        }).then(() => {
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    console.log(3);
                    resolve()
                }, 500)
            })
        }).then(() => {
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    console.log(4);
                    resolve()
                }, 200)
            })
        })

图示

 Promise的方法及属性

属性(内置属性 无法访问)

PromiseState 表示当前状态

PromiseResult 表示当前结果

方法

原型方法  返回的新的promise 里面有状态

then处理对应的promise状态变化

  • then有俩个参数函数 一个是成功的处理函数一个是拒绝的错误函数
  • 成功的处理函数里面可以接收对应的resolve函数调用携带的参数
  • 拒绝的处理函数里面可以接收对应的reject函数调用携带的参数
  • 拒绝的处理函数还可以捕获的对应的promise中抛出的错误
  • 在then中return的数据会被下一级的then方法接收
  • then里面会发生值穿透 (上层的then方法没有对应的函数做为参数)

        let promise = new Promise((resolve, reject) => {
            console.log('hello')
            //promise的状态是唯一的
            // resolve(123) //成功状态
            // return 123 //状态没有发生变化 不会调用then
            // reject(456) //拒绝状态
            throw new Error('你好错了')
            //then方法 它里面传入俩个参数 (都是函数)
            //第一个参数为成功的处理函数(携带 resolve函数传递的数据 相当于接收了return的数据return也会调用的对应的then)
            //第二个参数为拒绝的处理函数(携带 reject函数传递的参数 或者 捕获抛出的错误)
        }).then((result) => {
            console.log(result)
        }, (err) => {
            console.log(err)
        })
        //then的传值 使用return
        new Promise((resolve) => {
            resolve()
        }).then(() => {
            return 123
        }).then((result) => {
            console.log(result)//123
        })
        //then的值穿透 发生在上层的then方法里面没有函数为参数
        new Promise((resolve) => {
            resolve('hello')
        })
            // .then(()=>{}) 只有有参数不会发生值传统
            .then()
            .then()
            .then((result) => {
                console.log(result)//123
            })

catch 捕获promise错误 以及获取对应的promise的reject方法调用的结果 (跟then方法中的第二个
参数一模一样)

        new Promise((resolve, reject) => {
            // reject(11)
            throw new Error('我错了')
        }).catch((err) => { //接收reject函数调用的参数 或者捕获对应的错误
            console.log(err)
        })
        //catch也会发生值穿透
        new Promise((resolve, reject) => {
            // reject(11)
            throw new Error('我错了')
        }).catch()
            .catch()
            .catch((err) => { //接收reject函数调用的参数 或者捕获对应的错误
                console.log(err)
            })

finally 状态发生变化就会调用的函数

        //finally 不管成功还是失败都会调用的函数(状态变化)
        new Promise((resolve, reject) => {
            resolve(111)
            // reject(11)
            // throw new Error('我错了')
        }).finally(() => {
            console.log('完成了')
        })

静态方法  返回的是一个新的promise

resolve 产生一个成功状态的promise

        //返回成功状态的promise resolve
        let promise1 = Promise.resolve(456)
        console.log(promise1)
        promise1.then((result) => {
            console.log('成功了' + result)
        })

reject 产生一个为失败(拒绝)状态的promise

        //reject方法 产生一个拒绝状态的promise
        let promise2 = Promise.reject(123)
        console.log(promise2)
        promise2.catch((err) => {
            console.log(err)
        })

race 竞速 (传入一个promise数组 返回的是执行最快的promise)


        //竞速方法race 比较执行速度 谁先执行完(不区分成功失败)返回执行快的promise
        let promise3 = Promise.reject(1)
        let promise4 = Promise.reject(2)
        // let promise3 = Promise.resolve(1)
        let newPromise = Promise.race([promise3, promise4]) //成功状态比拒绝状态要快
        console.log(newPromise)

all 并行执行传入的promise数组(遇到rejected那么就获取rejected的promise  成功则会接所有的promise结果)


        //all 同步并行执行多个promise 返回一个promise ( 全部成功 包含所有的结果 状态为成功)
        // (如果遇到了拒绝那么返回的就是拒绝状态的 只会接收到拒绝传递的值)
        let promise5 = Promise.reject(5)
        let promise6 = Promise.reject(6)
        let promise7 = Promise.reject(7)
        // let promise7 = Promise.resolve(7)
        let promise8 = Promise.reject(8)
        let promiseAll = Promise.all([promise5, promise6, promise7, promise8])
        console.log(promiseAll)

allsettled 并行执行传入promise数组 (只要执行完成那么返回都是对应的成功状态 且会接收所
有的promise结果)


        //allSettled 并行执行多个promise 返回所有的结果 (只要执行完成那么状态就是成功) 新增的
        let promiseAllsettled =
            Promise.allSettled([promise5, promise6, promise7, promise8])
        console.log(promiseAllsettled)

async及await

概述:

async及await是es7新增的修饰关键词,async是用于修饰对应的函数的,被async修饰的函数 执行会返回一个promise对象,awiat和async属于语法糖 (awiat一定要在async里面使用 awiat修饰的是promise

ansyc

概述

async表示异步、async是用于修饰函数的 且修饰的函数调用会返回一个promise对象

注意事项

  • 修饰的函数内容返回值相当于调用了resolve方法 返回的值会被传递给then
  • 在修饰函数内报错相当于调用了reject方法 错误会被传递给catch
        // async及await
        //async用于修饰对应的函数的 异步
        async function sayHello() {
            console.log('123')
            //因为它返回的值 在async修饰的函数内容 返回内容相当于调用了resolve方法 更改状态为成功
            //报错相当于调用了reject
            // throw new Error() 相当于 reject调用
            //函数默认返回undefined
            // return 123 相当于resolve调用
        }
        //async修饰的函数调用会返回一个promise对象
        let promise = sayHello()
        console.log(promise)
        promise.then((result) => {
            console.log(result)
        })

awiat

概述

awiat是用于修饰promise的,它只能在async修饰的函数内使用,它会让当前的js引擎线程在当前的执行上下文中等待,当前修饰promise的状态不为pending的时候就会释放。

        async function say() {
            //使当前js引擎线程等待 等待对应的状态更改才释放
            await new Promise((resolve, reject) => {
                setTimeout(() => {
                    console.log(1);
                    resolve()
                }, 2000)
            })
            console.log(2)
        }
        say() // 1 2

使用async和awiat解决回调地狱

        // 使用async和awiat解决回调地狱
        async function test() {
            //使当前js引擎线程等待 等待对应的状态更改才释放
            await new Promise((resolve, reject) => {
                setTimeout(() => {
                    console.log(1);
                    resolve()
                }, 2000)
            })
            await new Promise((resolve, reject) => {
                setTimeout(() => {
                    console.log(2);
                    resolve()
                }, 1000)
            })
            await new Promise((resolve, reject) => {
                setTimeout(() => {
                    console.log(3);
                    resolve()
                }, 500)
            })
            console.log(4)
        }
        test()

EventLoop(事件轮询)

概述:eventLoop事件轮询,针对于对应的异步任务的执行相关操作(定时器、事件、请求....)。

事件队列

队列是先进先出一个数据结构,事件队列就是其异步任务的一个队列(先进去先执行 后进行后执行)

执行栈

栈是一个先进后出的一个数据结构,它主要用执行对应的js代码。

事件队列的分类

宏任务 (大的任务 线程直接分配的)

script 标签 定时器(setInterval,setTimeout)...

微任务 (小的任务)

promise.then promise.catch promise.finally

宏任务进入宏任务队列 微任务进入微任务队列
eventLoop主要是控制宏任务队列的任务执行及微任务队列的任务执行

  • 先宏后微
  • 一个个的宏任务走进再走其包含的微任务

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值