js 闭包和promise

闭包

概述:

闭包就是在函数内部返回一个函数,内部函数可以对外部函数的属性和方法进行引用,外部的属性和方法不会被js垃圾回收机制所回收 这个结构就称为闭包

函数的生命周期

function fn(){
      var i=0
      i++
      return i
    }
    console.log(fn());//1 第一个i变量
    console.log(fn());//1 第二个i变量
    console.log(fn());//1 第三个i变量

函数在预编译阶段做的事情

  • 开辟一个内存空间
  • 将对应的代码块放到这个内存空间

函数的执行阶段

  • 将对应的函数开辟的这个空间放在执行栈上

  • 执行栈就开始执行对应的函数对应的空间的代码块

  • 这个代码如果需要开辟空间 它就在这个对应的这个函数的内存空间上开辟

  • 当你不需要使用这个函数了 对应的函数的内存空间就会被回收 那么里面的代码开辟的空间也就被回收了

如果我们需要保持i的状态 那么我们可以将这个i放到这个引用数据类型里面 然后保证这个引用数据类型对象的引用,这个时候gc就不会回收对应的这个i了

function fn(){
      var i=0
      i++
      return{
        i
      }
    }
    var obj=fn()
    console.log(obj.i);//1

通过上述代码 我们可以保持对应i的引用,保证i不会被回收,以返回一个引用数据类型来保持对应i的引用。 那么对应的函数也是一个引用数据类型,那么我们是不是也可以通过返回函数的形式来做到保证i的唯一性。

function fn(){
  var i = 0
  return function(){
      i++
      console.log(i)
  }
}
var f = fn()
f() //1
f() //2 
f() //3

闭包的优劣

优势
  • 内部函数拥有外部函数参数和变量的引用,使用我们的参数和变量的作用范围被扩大。

  • 对应的参数不被回收,在使用的时候就不需要重新开辟空间,速度更快。

  • 作为缓存

劣势
  • 内部函数要一直保持对外部函数里面参数和变量的引用。

  • 因为不会被回收那么对应的内存空间就会一直占用。

闭包的应用

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

示例 (等电梯)

function debounce(fn,delay){
      //假设电梯没人
      var timer = null
      return function(){
        clearTimeout(timer)//清除上一次的等待
        //开始新的等待
        timer=setTimeout(fn,delay)
      }
    }

节流(在规定间隔时间内执行一次,减少执行次数)

示例 (高铁上厕所)

function throttle(fn,delay){
      //假设厕所没人
      var timer=null
      return function(){
        //判断厕所是否有人
        if(timer) return //如果没有 就上 
        //如果有人
        timer=setTimeout(()=>{
          fn()
          //上完了要将节流阀设置为false
          timer=null
        },delay)
      }
    }
防抖和节流的区别
  • 防抖执行最后一次 节流执行第一次

  • 防抖在规定时间内只执行一次 节流是在规定时间内减少对应的执行次数

  • 防抖对应的开始下一次先要清除上一次 节流开始下一次先要判断上一次是否执行完毕

函数柯里化 (将多个参数的函数拆分为多个单参数的函数 可以自由的组合)
//传递一个函数 (参数没到返回函数 参数到了返回结果)
function currying(fn) {
    //获取currying传递的参数
    let args = Array.prototype.slice.call(arguments,1)
    return function () {
        //将对应的函数的参数和curry传递参数做连接
        let arg = Array.from(arguments).concat(args)
        //判断参数个数是否一样
        if(arg.length < fn.length){
            //参数没到返回函数
            return currying.call(this,fn,...arg)
        }else{
            //参数到了 调用方法返回结果
            return fn.apply(this,arg)
        }
    }
}

调用

function sum(a,b,c){
    return a+b+c
}
console.log(`sum(1,2,3)`, sum(1,2,3));
let fn = currying(sum)
console.log(`fn(2)`, fn(2));//函数
console.log(`fn(2)(3)`, fn(2)(3));//函数
console.log(`fn(2)(3)(1)`, fn(2)(3)(1));//6
console.log(` fn()()()(2)()()(3)()()()(1)`, fn()()()(2)()()(3)()()()(10));//15

Promise

概述:promise是es6新增的一个类,这个类翻译为承诺,它有三种状态 等待状态,成功状态,拒绝状态。它被设计为异步的,它里面的内容是异步的(方法为异步的)

promise的三种状态

  • 等待状态(没有处理) pending

  • 成功状态 (有对应的处理) fulfilled (里面resolve方法调用)

  • 失败状态 (有对应的处理)rejected (里面代码报错 或者 调用reject)

构建promise对象

new Promise((成功的函数,失败的函数)=>{
    代码块
})
//里面传递的参数是一个函数
//这个传递的函数里面有俩个参数 这个俩个参数也是一个函数
//这个函数里面的第一个参数为成功的函数 resolve  第二个参数为失败的函数 reject (这个俩个函数都是异步的)
var promise = new Promise((resolve,reject)=>{
    //包含异步的代码
    console.log('hello promise')
})

promise的方法

then 执行成功的回调

catch 执行失败的回调

finally 执行完成调用的

静态方法
  • resolve (返回成功状态的promise)

  • reject (返回失败状态的promise)

  • all (并行执行所有的promise 如果遇到rejected就返回reject的promise 如果全部成功就返回所有的结果(promiseresult))

  • allSettled (互不影响执行对应的promise 返回所有的结果(状态一定是成功))

  • race (返回最快执行完成的promise)

//静态方法 Promise.方法名
//resolve方法
//返回一个成功的promise对象
var promise = Promise.resolve('hello')
console.log(`promise`, promise);
promise.then(res=>{
    console.log(res);
})
// reject返回一个失败的promise对象
var promise1 = Promise.reject('错误')
console.log(`promise1`, promise1);
promise1.catch(error=>{
    console.log(error);
})
//all 传入一个promise数组 并行执行promise数组里面的promise (如果有一个是rejected 那么整体都是rejected)
var promise2 = Promise.resolve('hello')
var promise3 = Promise.reject('错误')
// var promise3 = Promise.resolve('成功')
var promise4 = Promise.resolve('world')
var promise5 = Promise.resolve('你好')
//all方法返回的是一个promise对象 如果全部成功对应的promiseResult里面的结果就是所有成功 否则就是错误的结果
var promise6 = Promise.all([promise2,promise3,promise4,promise5])
console.log(promise6);
//传入一个promise数组 返回一个promise对象  不会互相影响 返回所有结果(状态为成功)
var promise7 = Promise.allSettled([promise2,promise3,promise4,promise5])
console.log(promise7);
//竞速 race  传入promise数组 返回最快走完的promise
var  promise8 =  Promise.race([promise2,promise3,promise4,promise5])
console.log(promise8);

回调地狱

概述:回调函数的无限嵌套导致当前代码失去了对应的维护价值及对应的可读性。

promise来解决回调地狱(链式调用)

在.then里面返回一个新的promise对象 在对应的异步代码执行完后调用resolve

//利用promise来解决回调地狱的问题
new Promise((resolve, reject) => {
    setTimeout(() => {
        console.log(1);
        resolve()
    });
}).then(() => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log(2);
            resolve()
        });
    })
}).then(()=>{
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log(3);
            resolve()
        });
    })
}).then(()=>{
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log(4);
            resolve()
        });
    })
}).then(()=>{
    console.log(5);
})

代码执行机制

同步代码执行比异步代码快

同步代码的执行是利用对应的js引擎解析的

异步代码执行是利用事件轮询机制执行的

事件轮询机制
  • 先找script标签里面的微任务

  • 按照微任务队列执行完对应的微任务

  • 进入下一个宏任务 执行对应的宏任务代码

  • 进行宏任务对应微任务队列 执行对应微任务

  • 再进行到下一个宏任务 执行对应的微任务

  • 直到对应的宏任务队列和微任务队列被清空

宏任务

script 定时器(setInterval setTimeout) 事件...

微任务

promise.then promise.catch nextTick ....

posted @ 2022-11-09 19:31  一棍一行小代码  阅读(76)  评论(0编辑  收藏  举报