闭包 及promise

223 阅读7分钟

闭包

概述

闭包就是函数嵌套函数,内部函数拥有外部函数的引用,导致这个引用无法被GC回收。

作用域 (上下文对象)

全局作用域

在全局作用域内声明的函数或者变量 都属于当前的全局对象(global对象)

局部作用域

在函数作用域内声明的变量或者形参 都是归属于当前的上下文对象(context 对象 )

函数的执行流程

预编译====>调用执行(通过栈地址找到对应的函数执行上下文)

预编译
全局变量的预编译
  • 创建对应的GO对象(global object)
  • 形参和变量赋值 指定默认值为undefiend
  • 形参和实参同步
  • 找到函数声明,将对应的值给到函数体
局部变量的预编译
  • 创建对应的AO对象(activation object 执行上下文对象)
  • 形参和变量赋值当做AO的属性 形参和变量赋值指定默认值为undefiend
  • 形参和实参同步
  • 找到函数声明,将对应的值给到函数体
GC(垃圾回收机制)

不能自动调用

标记清除法 (通过标记的形式进行回收 如果当前的值没有变过,没有被使用过就会被回收)(var 一个a 不赋值 )

引用计数(通过不断计数来操作进行回收 被使用就+1 没有人用就-1 到0就会被回收

image.png

普通函数自增示例

通过以上讲解发现如果需要让函数内的参数不回收 那么需要保持对应的引用 使他一直存在,通过对应的函数内容返回引用数据类型的形式可以帮助我们保持对应的引用。也就是说通过这种方式就可以使对应的内容不回收 函数也是一个引用数据类型 所以他同样保证不被垃圾回收机制回收 ( 用函数的形式 不断的调入全局 使其不被回收)

闭包的特点

保持引用,数据进行缓存,不被垃圾机制回收。

用途

  • 作为缓存 (缓存数据量小 .加载快 )
  • 节流
  • 防抖
  • 函数柯里化

闭包的优缺点

优点

  • 保持了引用 内容不需要重新创建 加载速度快
  • 扩大了函数内参数 或者变量的作用范围
  • 利用内部函数来访问外部函数的参数 或者变量,避免了数据污染

缺点

  • 内存占用大(一直保持引用 ,不回收),滥用容易造成内存泄漏.
  • 通过返回函数的形式进行调用 需要不断开辟函数空间 容易内存溢出
防抖 (只执行一次 防止高频触发) (提交表单 确认登录 )

概述

在规定时间内只执行一次,执行的时候最后一次。

示例

电梯关门时间为10秒,A同学进入电梯点击关闭电梯需要等待10秒,b同学过来进来了 进入电梯等待10秒,c同学进入电梯中断了,最后执行的完整关门操作由c来执行。

image.png

代码实现

image.png

节流 (减少触发次数) (如轮播图)

在限定时间内执行一次,执行第一次

示例

高铁内上厕所,如果有人亮红灯,没人亮绿灯,A看到亮绿灯进入上厕所变为红灯,上完厕所灯变为绿灯。B进入之前就需要查看当前亮什么灯(看测试是否有人).如果是红灯就回去。如果是绿灯就进入厕所灯油变成红灯,

image.png

函数柯里化

将多参数的函数分解成单一参数的函数,主要是可以延迟传入参数

函数柯里化优点

  • 延迟传入参数
  • 参数复用

参数柯里化核心

参数个数没到返回函数,参数个数到返回结果

简单函数柯里化

image.png

反柯里化

将本身没有的方法进行调用

简单反柯里化

image.png

image.png

Promise

概述 promise 是一个新增的类,最主要用处理异步问题(异步代码同步执行)主要解决了回调地狱问题,它翻译了为承诺,它有三种状态。

promise 的三种状态

  • 成功状态 (fifuling)
  • 失败状态 (rejected)
  • 等待(默认状态)(pending)

image.png

image.png

主要处理异步问题 是es6新增的一个类

promise类的实例化

使用new关键词进行实例化

image.png

promise的相关原型方法

  • finally 处理状态更改的方法

image.png

  • then 处理成功的方法
  • catch 处理失败状态的方法

image.png

总结

  • promise 的所有原型方法返回的都是一个新的promise对象
  • then方法允许传入两个参数 (参数类型为函数)他的第一个函数参数接收resove的处理 第二个函数参数接收reject的处理
  • cath接收对应的reject的处理,抛出错误它也可以接收
  • then和catch都会发生值穿透问题(传入参数非函数就会发生值穿透)
  • then和catch中如果return数据那么就会将数据传递给下一个then 如果抛出错误就会将数据传递给下一个catch
  • then里面的第一个函数可以接收resove调用传递的结果,第二个函数可以接收reject传递的结果 catch也可以接收reject传递的结果
  • finally 处理状态更改的方法(只要状态发生变化 他就会被调用)

promise 的静态方法

  • all 同步执行所有的promise 当一个错误返回结果为错误的那一个promise。 当成功就返回所有的结果 且状态为成功(走完)
  • race 竞速 返回一个最先执行完的promise结果(谁先执行谁)
  • reject 返回一个失败状态
  • resolve 返回一个成功状态
  • allesttled 同步非并行执行所有结果(promise) 不管是否成功失败都返回所有结果 且状态为成功

image.png

回调地狱

回调函数的无限嵌套 造成回调地狱

回调地狱主要是代码的可读性低

可维护性低 造成代码没有存在的价值

image.png

利用promise 来解决回调地狱

利用then方法 返回的是一个promise的特性 (无限调用then方法) 利用then方法中调用teturn可以进行下一个then的特性

核心实现

在对应的then方法中调用teturn返回一个新的promise

image.png

image.png

ES7新增的async awiat

async awiat 是一个语法糖 asyc 是用于修饰函数的 (async 修饰的函数返回一个新的promise) awiat 适用于修饰promise 的(只能在async修饰的函数内使用)

image.png

image.png

eventLoop (事件轮询) js是单线程 (js引擎只有一个) 同步先执行 异步后执行

异步代码执行机制

其实就是由webApi进行任务队列(先进先出)的分发

任务队列的组成又分为宏任务队列和微任务队列

宏任务队列 (属于基础的异步代码 js.事件执行.定时器.延时器...)

  • 微任务队列(属于宏任务里面的promise 就是微任务)

  • 任务队列的执行机制被称为事件轮询

注意事项 先宏后微

  1. 先进入js的宏任务 然后在推入里面的同步代码 再去找对应的微任务队列
  2. 将对应的微任务队列的内容按照加入队列的顺序进行 推入执行栈,执行完所有的微任务 开启下一个宏任务。
  3. 如果当前宏任务 是setTimeout或者是setinterval那么这个执行的机制取决于间隔的时间(时间间隔取决于加载顺序)。 4.将当前的宏任务 里面的同步代码推入执行栈 在找到微任务队列 执行微任务...不断重复直到微任务及宏任务队列不断清空。

image.png