首页 > 其他分享 >day20 闭包和promise

day20 闭包和promise

时间:2022-10-26 20:55:09浏览次数:46  
标签:闭包 resolve console log day20 promise fn 函数

闭包 ( Closure )

概述 : 闭包就是函数嵌套函数 , 内部函数可以引用外部函数的变量和参数 , 并且不会被垃圾回收机制所回收 . 这种结构就称为闭包 .

函数的生命周期
function fn(){
    var i = 0
    i++
    return i
} 
console.log(fn()) //1 第1个i变量
console.log(fn()) //1 第2个i变量
console.log(fn()) //1 第3个i变量
函数在预编译阶段
  • 开辟一个内存空间

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

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

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

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

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

如果我们需要保持 i 的状态 , 那么我们可以将这个 i 放到这个引用数据类型里面 , 然后保证这个引用数据类型一直被引用 , 这个时候gc就不会回收这个 i 了
function fn(){
    var i = 0
    i++
    return {
        i
    }
}
var obj = fn()
console.log(obj.i) //1

由上可知 , 我们可以保持对 i 的引用 , 就可以保证 i 不会被回收 , 以返回一个引用数据类型来实现 . 由于函数也是一个引用类型 , 那么我们也可以通过返回函数的形式来做到保证 i 的唯一性

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

而上面这种保证 i 不会被回收的机制就叫做闭包 ( 返回一个引用数据类型 , 这个里面保证 i 的引用 , 从而不被回收 )

闭包的优劣

优势

  • 内部函数可以引用外部函数的参数和变量 , 使我们的参数和变量的作用范围被扩大

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

  • 作为缓存

劣势

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

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

闭包的应用
  • 防抖 ( 在规定时间内只执行一次 , 执行最后一次 ) ,防止重复点击

示例 ( 等电梯 )

//第一个参数fn是做的操作,第二个参数是等待时间
function debounce(fn,delay){
    var timer = null
    return function(){
        clearTimerout(timer) //清除上一次的等待
        //开始新的等待
        timer = setTimerout(fn,delay)
    }
}
  • 节流 ( 在规定时间内执行第一次 , 减少执行次数 )

示例 ( 红绿灯 )

//操作 执行一次的时长
function throttle(fn,delay){
    var timer = null
    return function(){
        //判断上一次是否走完
        if(timer) return 
        //上一次走完了开始下一次
        timer = setTimeout(()=>{
            fn()
            //走完了将节流阀关掉
            timer = null
        },delay)
    }
}

防抖和节流的区别

  • 防抖执行最后一次 , 节流执行第一次

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

  • 防抖开始下一次会先清除上一次 , 节流开始下一次会先判断上次是否走完 , 走完了再开始执行下一次

 

函数柯里化 ( 将多个参数的函数拆分为多个单参数的函数 , 可以自由的组合 )

核心 就是参数不够就返回对应的函数 , 参数够了就返回结果

示例

function sum(a,b){
    return a+b
}
sum(1,3)
  • 简单的函数柯里化
function sum(a){
    return function(b){
        return function(c){
            return a+b+c
        }
    }
}
console.log(sum(4)(3)(2))
console.log(sum(4)(3))
  • 高阶函数柯里化
// 函数的柯里化
// 先传递一个fn函数,用来判断参数的个数是否相等(参数数量相等就返回结果,不够就返回对应的函数)
function currying(fn) {
    // 获取currying传递的参数
    let args = Array.prototype.slice.call(arguments, 1)
    return function () {
        // 将返回的函数的参数和currying传递的参数做连接
        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的参数(有3个)赋给fn
let fn = currying(sum)
console.log(fn(2)) //个数不够,返回函数
console.log(fn(2)(3)) //个数不够,返回函数
console.log(fn(2)(3)(1)) 6
// 位置可更改
console.log(fn()()(2)()()(3)()()(10)) //15

 

Promise

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

promise的三种状态

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

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

  • 拒绝状态 ( 有对应的处理 ) rejected ( 代码报错或者调用reject )

构键promise对象
new Promise((成功的函数,失败的参数)=>{
    代码块
})
//promise里面传递的参数是一个函数
//这个传递的参数有2个参数,他们的参数也是函数
//第一个函数是成功的函数(resolve),第二个是失败的函数(reject),这两个函数都是异步的
var promise = new Promise((resolve,reject)=>{
    //包含异步的代码
    console.log('hello promise') //同步代码
    resove() //异步的
    reject() //异步的,会报错
})
//在new promise里面的同步代码在开始就会调用
console.log('promise')
//在promise里面如果报错 就是rejected

 

promise的方法

原型方法
  • then 执行成功的回调

//promise只能满足于一种状态,进入到成功就成功了,失败就不会调用
var promise = new Promise((resolve, reject) => {
    // 成功的函数和失败的函数调用,都可以传参
    resolve('成功了')
    reject('失败了')
})
// then的链式调用,默认只有第一个能接收到resolve的参数,如果后面也想接收,就需要return
promise.then((res) => {
    console.log('第1次then', res) //成功了
    return '成功成功'
})
    .then((res) => {
    console.log('第2次then', res) //成功成功
    return '成功成功'
})
    .then((res) => {
    console.log('第3次then', res) //成功成功
    return '成功成功'
})
    .then() //值穿透 当你的then没有处理,它会给到下一个来处理
    .then((res) => {
    console.log('第n次then', res) //成功成功
})
  • catch 执行失败的回调
//promise只能满足于一种状态,进入到成功就成功了,失败就不会调用
var promise = new Promise((resolve, reject) => {
    // 成功的函数和失败的函数调用,都可以传参
    // resolve('成功了')
    reject('失败了')
})
// catch的链式调用,默认情况下只有第一个接收reject的参数,如果后面也想接收,就需要报错
promise.catch((error) => {
    console.log('第1次catch', error) //失败了
    throw new Error('报错报错')
})
    .catch((error) => {
    console.log('第2次catch', error) //报错报错
    throw new Error('报错报错')
})
    .catch((error) => {
    console.log('第3次catch', error) //报错报错
    throw new Error('报错报错')
})
    .catch() //值穿透 当你的catch没有处理,它会给到下一个来处理
    .catch((error) => {
    console.log('第n次catch', error) //报错报错
})
  • finally 完成就调用 ( 成功或失败 )
//promise只能满足于一种状态,进入到成功就成功了,失败就不会调用
var promise = new Promise((resolve, reject) => {
    // 成功的函数和失败的函数调用,都可以传参
    resolve('成功了')
    // reject('失败了')
})
// finally的链式调用
promise.finally(() => {
    console.log('第1次finally',promise) //成功了
})
    .finally(() => {
    console.log('第2次finally',promise) //成功了
})
    .finally(() => {
    console.log('第3次finally',promise) //成功了
})
    .finally() //值穿透 当你的finally没有处理,它会给到下一个来处理
    .finally(() => {
    console.log('第n次finally',promise) //成功了
})

var success = new Promise((resolve, reject) => {
    // 成功的函数调用,可以传参
    resolve('成功了')
    reject('失败了')
    // throw new Error() //抛错
})
// 成功的回调then,有两个参数,分别是成功的函数和失败的函数

success.then((res) => {
    console.log(res)//res会接收resolve传递的参数 //成功了
}, (error) => {
    console.log(error)//接收reject传递的参数 //失败了
})
// 失败的回调catch,只有一个参数,也是函数,这个函数可以接收reject传递的参数
success.catch((error) => {
    console.log(error) //失败了
})
// 完成(成功或失败)就调用,没有参数
success.finally(() => {
    console.log('完成了')
})

then catch finally 都是返回一个promise对象,支持链式调用

静态方法

Promise.方法名

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

// resolve方法
// 返回一个成功的promise对象
var promise = Promise.resolve('hello')
console.log(promise)
promise.then(res => console.log(res))
  • reject ( 返回失败状态的promise )
// reject方法
// 返回一个失败的promise对象
var promise1 = Promise.reject('错误')
console.log(promise1)
promise1.catch(error => console.log(error))
  • all ( 传入一个promise数组 , 并行执行所有的promise数组 , 返回的是一个promise对象 ,
  • 如果遇到rejected就返回拒绝的promise状态 , 如果全部成功就返回所有的结果 ( promiseResult ) )
// all方法
// 传入一个promise数组,同时执行promise数组里的promise,如果有一个是rejected,那么整体都是rejected,如果全部成功,那么对应的promiseResult的结果就是成功并显示内容
var promise2 = Promise.resolve('成功')
var promise3 = Promise.reject('失败')
var promise4 = Promise.resolve('成功')
var promise5 = Promise.resolve('成功')
var promise6 = Promise.all([promise2, promise3, promise4, promise5])//失败rejected
var promise7 = Promise.all([promise2, promise4, promise5]) //成功
console.log(promise7)
  • allSettled ( 传入一个promise数组 , 返回的是一个promise对象 , 执行的promise 不会互相影响 , promiseResult返回所有结果 ( 状态为成功 ))
// allSettled方法
// 传入一个promise数组,数组内的成功与否不会被影响,返回所有的promiseResult结果,状态为成功
var promise8 = Promise.allSettled([promise2, promise3, promise4, promise5])
console.log(promise8)
  • race ( 传入一个promise数组 , 返回最快走完的promise对象)
// race方法 
// 竞速,传入promise数组,返回最快完成的promise
var promise9=Promise.race([promise2, promise3, promise4, promise5])
console.log(promise9)

promise的三种状态图

回调地狱

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

示例

// 传入一个函数作为回调函数,在对应的代码执行完成后调用
function fn(fn){
    setTimeout(()=>{
        console.log(10)
        // 走完了以后回调函数执行
        fn()
    },1000)
}
fn(()=>{
    console.log(1)
})
// 多个函数嵌套,会造成回调地狱,它会让代码不方便维护与理解
fn(()=>{
    console.log(1)
    fn(()=>{
        console.log(2)
        fn(()=>{
            console.log(3)
            fn(()=>{
                console.log(4)
                fn(()=>{
                    console.log(5)
                    ...
                })
            })
        })
    })
})
  • 利用 promise 来解决回调地狱 ( 链式调用 )
// 利用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)
})

 

async await ( es7新增的 )

概述 :

  • async和await是两个连用的关键词 ,

  • async是修饰函数的 , await是修饰promise的

  • await只能再async内使用 ,

  • async修饰的函数会返回一个promise对象 , await修饰的promise对象会占用当前的线程 , 直至对应的promise执行完成后才会释放 .

async function fn(){
    await new Promise((resolve,reject)=>{ //如果没有放行后面的代码不会执行
        setTimeout(()=>{
            console.log('hello')
            resolve()
        })
    })
    console.log('world') //先执行hello,后执行world
}
// async修饰完函数 执行会返回一个promise对象
console.log(fn()) //promise对象
// 这个promise对象 如果里面有一个报错或rejected,那它整体的promise对象状态都为rejected
// 如果里面return内容,那么它将会传递给对应的then
async function fn1(){
    throw new Error('错误')
    // return '我是007'
}
fn().then(res => {
    console.log(res) //我是007
},error=>{
    console.log(error) //错误
})
// await会使当前函数的线程被占用,知道对应修饰的promise执行完成
// await Promise.reject() 报错
  • 利用async和await解决回调地狱
function fn(v,delay){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            console.log(v)
            resolve()
        },delay)
    })
}
async function fn1(){
    await fn(1,1000)
    await fn(2,2000)
    await fn(3,100)
    await fn(4,0)
    console.log(5)
}
fn1()

 

总结
  • async修饰函数的

  • await修饰promise对象的

  • await要在async里面使用 , 如果这个await修饰的promise没有执行完 , 那么async修饰的函数返回promise状态是等待状态

  • 如果async修饰的函数内什么都没有那么promise返回的状态是成功 ( 默认函数返回是undefined )

  • async修饰的函数 , 如果返回值是成功 , 那么这个值会传递给then方法

  • async修饰的函数 如果有报错 , 那么返回的是失败 , 传递的值就是报错

  • await只能再saync里面使用 , await会使当前的函数陷入等待

代码执行机制

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

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

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

事件轮询机制

 

 

 

 

script标签是最大的宏任务

  • 先找script标签里的微任务并按照任务队列执行

  • 再进入到下一个宏任务 , 继续执行对应的宏任务代码

  • 执行完后再进入宏任务内的微任务,继续执行它的微任务代码

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

  • 直到所有的宏任务队列和微任务队列被清空

宏任务

script , 定时器 ( setTimout , setInterval ) , 事件 ...

微任务

promise.then , promise.catch , nextTick

标签:闭包,resolve,console,log,day20,promise,fn,函数
From: https://www.cnblogs.com/itlulu/p/16829996.html

相关文章

  • day20闭包和promise
    闭包概述:在函数内返回一个函数(函数嵌套函数),内部函数有外部函数的引用。函数的生命周期函数的预编译阶段:1.开辟一个内存空间2.将对应的代码放到这个内存空间函数的执......
  • promise和async
    promise和async由于javascript是单线程的,只能在JS引擎的主线程上运行的,所以js代码只能一行一行的执行,不能在同一时间执行多个js代码任务,这就导致如果有一段耗时较长的计......
  • 闭包和promis
    一.什么是闭包(闭包的原理)闭包的形成与变量的作用域以及变量的生存周期密切相关,变量的作用域,就是指变量的有效范围。生存周期对于全局变量是永久的,除非我们主动销毁这个......
  • 彻底理解闭包实现原理
    前言闭包对于一个长期写Java的开发者来说估计鲜有耳闻,我在写Python和Go之前也是没怎么了解,光这名字感觉就有点"神秘莫测",这篇文章的主要目的就是从编译器的角度来......
  • JS知识点梳理之作用域、作用域链、柯里化、闭包
    一、作用域与作用域链作用域是指js变量使用时所存在的一个区域,分为全局作用域(window)和局部作用域(function、setTimeout...等都会产生局部作用域)。当局部作用域变量名与......
  • JavaScript高级程序设计笔记11 期约与异步函数(Promise & Async Function)
    期约与异步函数ES6新增Promise引用类型,支持优雅地定义和组织异步逻辑。ES8增加了使用async和await关键字定义异步函数的机制。异步编程JavaScript这种单线程事件循环模......
  • Netty入门-Future & Promise
    3.3、Future&PromiseNetty中的Future与Jdk中Future同名,但是是两个接口,继承关系:Promise---extends-->Future(Netty)-----extend--->Future(JDK)区别:jdkFuture只能......
  • vue3引入onMounted后使用onMounted方法后控制台报错分析(Uncaught (in promise) TypeEr
    报错截图报错中已经大致的提示了,onmounted不是一个函数(方法),所以分析是vue没有找到,所以是引入的时候出了问题。Uncaught(inpromise)TypeError:(0,vue_reactivity__WEB......
  • 随便写一个promise
    functionmyPromise(fn){this.state='Pending'this.valuethis.resolve=function(){if(this.state!='Pending'){return......
  • 原型、原型链、优点////作用域、作用域链////闭包、应用场景、优点、存在的问题
    一、原型、原型链、优点1、原型:在javascript中,函数可以有属性。每个函数都有一个特殊的属性叫做原型(prototype)2、原型链:JavaScript常被描述为一种基于原型的语言(prototy......