day20 闭包和promise

闭包

概述:闭包就是函数内部返回一个函数,内部函数有外部函数的引用,这个结果称为闭包.
函数的生命周期

functon fn(){
	var i = 0
	i++
	return 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)

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

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

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

  • 内部函数拥有外部函数参数和变量的引用 ,使用我们的参数和变量的作用范围变大
  • 对应的参数不被回收,在使用时不需要重新开辟空间,速度更快.
  • 作为缓存
    劣势
  • 内部函数要一直保持对外部函数里面参数和变量的引用。
  • 因为不会被回收那么对应的内存空间会一直占用。

闭包的应用
防抖(在规定时间内只执行一次 执行最后一次
示例(等电梯)
day20 闭包和promise_第1张图片

//第一个参数是做的操作  第二个是等待时间
function debounce(timer,delay){
		var timer =null
		return function(){
			clearTimeout(timer)
			timer =setTimeout(fn,delay)
	}
}

节流 (在规定时间内执行第一次 减少执行次数)
示例(红绿灯)
day20 闭包和promise_第2张图片

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

防抖和节流的区别

  • 防抖执行最后一次,节流执行第一次
  • 防抖在规定时间内只执行一次,节流是在规定时间内减少对应的执行次数
  • 防抖对应的开始下一次先要清除上一次 节流开始下一次先要判断上一次是否执行完毕

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

function sum(a,b){
	return a+b
}
console.log(sum(1,2)) //结果3

简单的函数柯里化

 function sum(a) {
            return function (b) {
                return function (c) {
                    return a + b + c
                }
            }
        }
      console.log(sum(1)(2)); //结果是函数
      console.log(sum(1)(2)(3));//结果是6

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

高阶函数柯里化

//传递一个函数 (参数没到返回函数 参数到了返回结果)
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新增的一个类,这个类翻译为承诺,它有三种状态 等待状态 成功状态 拒绝状态 .它被设计为异步的,它里面的内容是异步的(方法为异步)
day20 闭包和promise_第3张图片

promise的三种状态

  • 等待状态(没有处理) pending
  • 成功状态(有对应的处理) fulfilled (里面resolve方法调用)
  • 失败状态 (有对应的处理) rejected (里面 reject方法调用或者里面代码报错)

构建promise对象

new promise (成功的函数,失败的函数)=>{
	代码块
}
//里面传递的参数是一个函数
//这个传递的函数里面有俩个参数 这个俩个参数也是一个函数
//这个函数里面的第一个参数为成功的函数 resolve 第二个参数为失败的函数 reject (这个俩个函数
都是异步的)
  var promise = new Promise((revlose,reject)=>{
        console.log('我是默认的'); //pending  结果是undefined
        // revlose('我是成功了') //状态fulfilled  结果是我是成功了
        // reject('我被拒绝了')//状态是rejected  结果是我被拒绝了
        // throw new Error('我是个错误')  //状态是rejected 结果是我是个错误
       })
       console.log(promise);

promise的方法
原型方法

  • then 执行成功的回调
//第一个为成功的函数 第二个为失败的函数
var promise = new Promise((resolve, reject) => {
            resolve('我成功了')
            // console.log('哥是默认的');
            // reject('我失败了')
            // throw new Error('我是个错误')
        })
        promise.then((a) => {
            console.log('嗯', a);  //结果为成功的 嗯 我
        }, (b) => {
            console.log('哦', b); //结果为失败的
        })

then的注意事项

  • then括号里的也是两个函数,也可以只传一个.
  • then括号里为第一个为成功函数的调用,第二个为失败的函数的调用
  • then返回的值不能是promise 本身,否则会造成死循环.
  • 传入非函数会发生值穿透.
var promise = new Promise((resolve,reject)=>{
//成功的函数调用 传递对应的参数
resolve('成功')
})
promise.then((res)=>{
console.log(`第一次then`, res);
return 'hello'
}).then((res)=>{
console.log(`第二次then`, res);
return 'world'
}).then((res)=>{
console.log(`第三次then`, res);
return 'abc'
}).then() //值穿透 当你的then没有处理它会给到下一个处理
.
then((res)=>{
console.log(`第n次then`, res);
})

注意事项

  • .then 通过 return 连接
  • return的内容 会加入到下一个then里面去

catch 执行失败

 var promise = new Promise((resolve, reject) => {
            reject('失败')
            // throw new Error('失败了')
        })
        //.catch默认请求下只执行第一个 如果需要走下面的 那么需要你报错
        promise.catch(a => {
            console.log('俺不会', a);
            throw new Error('报错了')
        }).catch(a => {
            console.log('俺会了', a);
            throw new Error('给下个')
        }).catch(a => {
            console.log('哦', a);
            throw new Error('不要')
        }).catch()//值穿透哦
            .catch(a => {
                console.log('结束了不要往下给了', a);
            })

注意事项

  • 他是执行第二个失败函数的内容
  • 他也可以值穿透
  • throw new Error 的内容会加到下一个catch中

finally 执行完成调用的

//promise promise只能满足于一种状态 进入到成功它就成功了 进入失败就失败了
var success = new Promise((resolve,reject)=>{
//成功的函数调用 传递对应的参数
resolve('成功')
reject('失败')
// throw new Error('失败了')
})
//成功的回调 俩个参数 成功的函数 失败的函数
success.then((res)=>{//res会接收resolve传递的参数
console.log(`res`, res);
},(error)=>{//error 接收reject传递的参数
console.log(`error`, error);
})
//失败的回调 参数1个 传递为一个函数 这个函数可以接收rejected传递的参数
success.catch((error)=>{
console.log(`rejected`, error);
})
//完成就能调用的函数 (成功 失败)
success.finally(()=>{
	console.log(`完成了`);
})

静态方法

  • resvole (返回成功状态的promise)—fulfilled
  • reject (返回失败状态的promise)—rejected
  • all (执行所有的promise,如果遇到reject就返回reject的promiseresult 状态是rejected
  • 如果全部成功就返回所有成功的结果(promiseresult) 状态是fulfilled
  • allSettled (互不影响执行对应的promise 返回所有的结果 状态一定是成功 fulfilled
  • race (返回最快执行完成的promise)状态一定是成功 fulfilled

promise的三种状态图
day20 闭包和promise_第4张图片
回调地狱
概述:回调函数的无限嵌套导致当前代码失去了对应的维护价值及对应的可读性。
示例

//传入一个函数作为回调函数 在对应代码执行完成调用
function fn(fn) {
setTimeout(function () {
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);
fn(() => {
console.log(6);
....
})
})
})
})
})
})

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);
})

day20 闭包和promise_第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');
}
//async修饰完函数执行会返回一个promise对象
console.log(fn());
//async修饰的函数返回的promise对象
//里面的报错 会使当前的promise对象的状态为rejected
//如果里面return内容那么内容将会传递给对应的then
async function fn1(){
throw new Error('错误')
// return '我是fn1'
}
fn1().then(res=>{
console.log(res);
},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()

图例
day20 闭包和promise_第6张图片

总结

  • async修饰函数的
  • await修饰promise的
  • async里面使用await name如果这个await修饰的promise没有执行完,那么对应的async修饰的函数返回promise状态时pending。
  • 如果async修饰的函数内什么都没有那么对应返回的promise状态是成功(默认函数返回undefined)
  • async修饰的函数 返回值就是成功 返回的值传递给then方法
  • async修饰的函数如果里面报错 那么返回的是失败 传递的值为报的错
  • await只能在async里面使用 await会使当前的函数陷入等待

代码执行机制

同步代码执行比异步代码快
同步代码的执行是利用对应的js引擎解析的
异步代码执行是利用事件轮询机制执行的
事件轮询机制

你可能感兴趣的:(javascript,前端,开发语言)