闭包 ( 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