js:Promise理解、async和await的理解、宏任务/微任务、异常处理、防抖和节流
Promise理解、async和await的理解(未完成)、构造函数/原型/原型链、防抖和节流、this指向(普通函数,箭头函数,JS/Vue的this)、上下文环境、作用域和闭包
一、Promise
1、Promise的基本使用
Promise
对象代表一个异步
操作,有三种状态,只有异步操作的结果
,可以决定当前是哪一种状态。
这里只是new了一个对象,并没有调用它,我们传进去的函数就已经执行了
new Promise((resolve, reject) => {
// 异步工作处理
...
// 异步工作执行完之后
resolve(result) // ——如果成功完成,并返回结果result;
reject(error) // ——如果执行是失败并产生error;
})
2、一般都是结合函数使用
我们用Promise的时候一般是包在一个函数中,在需要的时候去运行这个函数
<div onClick={promiseClick}>开始异步请求</div>
const promiseClick =()=>{
console.log('点击方法被调用')
let p = new Promise(function(resolve, reject){
//做一些异步操作
setTimeout(function(){
console.log('执行完成Promise');
resolve('要返回的数据可以任何数据例如接口返回数据');
}, 2000);
});
return p
}
3、Promise的执行结果获取
语法:promise.then(function(result),function(error))
案例
let promise = new Promise((resolve, reject) => {
// 异步工作处理
...
// 异步工作执行完之后
resolve(result) // ——如果成功完成,并返回结果result;
reject(error) // ——如果执行是失败并产生error;
})
promise
.then(
(result) => {
console.log('成功执行,resolve(result)')
},
(error) => {
console.log('失败执行,reject(error)')
}
)
.catch(
// 区别:还可以获取到then的第一个函数的报错
(err)=>{console.log('等同于then的第二个error函数')}
)
4、Promise的链式编程
function myReadFile(path) {
return new Promise((resolve, reject) => {
fs.readFile(path, (err, data) => {
if (err) reject(err)
console.log(data.toString())
resolve(data)
})
})
}
myReadFile('1.txt') // 返回Promise
.then(data => { return myReadFile('2.txt') }) // 再次调用myReadFile,返回Promise
.then(data => { return myReadFile('3.txt') }) // 依次类推
.then(data => { return myReadFile('4.txt') })
.then(data => { return myReadFile('5.txt') })
.then(data => { return myReadFile('6.txt') })
.then(data => { return myReadFile('7.txt') })
.then(data => { return myReadFile('8.txt') })
.then(data => { return myReadFile('9.txt') })
.then(data => { return myReadFile('10.txt') })
注意:
promise.then()的返回值
其实是一个Promise对象
,这个新Promise的决议是等到then方法传入的回调函数有返回值时, 进行决议(要有return 数据)。- 当promise进行链式调用时promise.then().then(),第二个then的res其实是第一个then方法里的return的数据,包装成Promise。参考下面demo,理解链式调用
- catch()只需要一个就可以了,抛出异常可以用
throw new Error("第三个Promise的异常error")
const promise = new Promise((resolve, reject) => {
resolve("aaaaaaa")
// reject()
})
// 1.then方法是返回一个新的Promise, 这个新Promise的决议是等到then方法传入的回调函数有返回值时, 进行决议
// Promise本身就是支持链式调用
// then方法是返回一个新的Promise, 链式中的then是在等待这个新的Promise有决议之后执行的
promise.then(res => {
console.log("第一个then方法:", res) // 打印 "aaaaaaa"
return "bbbbbbbb"
}).then(res => {
console.log("第二个then方法:", res) // 打印 "bbbbbbbb"
return "cccccccc"
}).then(res => {
console.log("第三个then方法:", res) // 打印 "cccccccc"
}).catch(err => {
console.log("catch回调被执行:", err)
})
5、异步和同步
假设现在有A、B两个任务需要处理,使用并行、同步和异步的处理方式会分别采用如下图所示的执行方式:
6、Promise.all
Promise.all:多个异步请求,如果有一个错误,会在catch里返回错误结果,但多个请求仍然会发出请求。
应用场景:基本是在多个请求中【获取数据】时才会用到,直接提交的接口不要用Promise.all的
参数的执行顺序
和结果的返回顺序
执行顺序:谁执行的快谁先打印结果。
返回顺序:按照promise的添加顺序返回
function promise1 () {
return new Promise(resolve => {
setTimeout(() => {
resolve('1');
}, 10000);
})
}
function promise2 () {
return new Promise(resolve => {
setTimeout(() => {
resolve('2');
}, 1000);
})
}
Promise.all([promise1(), promise2()]).then(function(results){
console.log(results); // results:['1', '2']
});
二、async和await的理解
1、async
async是一个加在函数前的修饰符,被async定义的函数会默认返回一个Promise对象resolve的值
1.1 return:Promise对象
async function fun0(){
return new Promise(function(resolve,reject){
resolve('Promise对象')
})
}
console.log(fun0()); // Promise {<fulfilled>: 'Promise对象'}
fun0().then(res=>console.log(res)); // 通过then获取结果:Promise对象
1.2 return:常规变量(包装在Promise中)
async function fun0(){
return '常规变量';
}
console.log(fun0()); // Promise {<fulfilled>: '常规变量'}
fun0().then(res=>console.log(res)); // 通过then获取结果:常规变量
1.3 无返回值:返回underfind
async function fun0(){}
console.log(fun0()); // Promise {<fulfilled>: undefined}
fun0().then(res=>console.log(res)); // 通过then获取结果:undefined
2、await
await 也是一个修饰符,只能放在async定义的函数内。可以理解为等待。
2.1 await 修饰Promise对象
它会阻塞后面的代码,等Promise中返回的内容(resolve或reject的参数),且取到值后语句才会往下执行
async function fun(){
let a = await 1;
let b = await new Promise((resolve,reject)=>{
setTimeout(function(){
resolve('setTimeout')
},3000)
})
let c = await function(){
return 'function'
}()
console.log(a,b,c)
}
fun(); // 3秒后输出: 1 "setTimeout" "function"
2.2 await 不是Promise对象
把这个非promise的东西当做await表达式的结果。
(相当于没有await)
function log(time){ // 普通的异步函数
setTimeout(function(){
console.log(time);
},time)
}
async function fun(){
let a = await log(1000); // 按照异步函数的处理事件快慢决定打印殊勋
let b = await log(3000);
let c = log(2000);
console.log(a,b,c); // 先执行它,上面是三个都是异步,所以开始abc都是undefined
}
fun();
// 立即输出 undefined undefined undefined
// 1秒后输出 1000
// 2秒后输出 2000
// 3秒后输出 3000
3、promise和async/await 的区别
3.1 单一的Promise链,两者区别不大
// Promise 写法
function p(){
return new Promise((resolve,reject)=>{
setTimeout(()=>{resolve('Promise写法')},1000)
})
}
p().then(res=>{console.log(res)})
// async/await 写法
function a(){
return new Promise((resolve,reject)=>{
setTimeout(()=>{resolve('async/await写法')},1000)
})
}
async function fn() {
const res = await a()
console.log(res);
}
fn()
3.2 多个 Promise链,async/await阅读友好
// Promise 写法
function p(time){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
console.log('Promise写法' + time);
resolve('Promise返回数据')},time)
})
}
p(1000)
.then(res=>{return p(2000)})
.then(res=>{return p(3000)})
.then(res=>{return p(4000)})
.then(res=>{return p(5000)})
// async/await 写法
function a(time){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
console.log('async/await写法' + time);
resolve('async/await返回数据')},time)
})
}
async function fn() {
const res1 = await a(1000)
const res2 = await a(2000)
const res3 = await a(3000)
const res4 = await a(4000)
const res5 = await a(5000)
}
fn()
4、promise和async/await 正确用法
前两步骤都是一样的,promise直接执行,async/await 通过第三方函数执行
4.1 promise
- fn函数要
return
一个promise对象
:[return new Promise()]- 在promise对象中进行
异步处理
,通过resolve/reject
出去结果/错误- 调用fn函数,通过
then
方法获取结果/错误
4.2 async/await
- fn1函数要
return
一个promise对象
:[return new Promise()]- 在promise对象中进行
异步处理
,通过resolve/reject
出去结果/错误- 定义一个
async
fn2函数,函数里await
fn1函数- 通过
变量接收
fn1函数的结果调用
(执行)fn2 函数
三、宏任务/微任务
除了主任务栈,事件循环中并非只维护着一个队列,事实上是有两个队列:
- 宏任务队列(macrotask queue):
ajax
、setTimeout
、setInterval
、DOM监听
、UI Rendering
等 - 微任务队列(microtask queue):
Promise的then回调
、Mutation Observer API
、queueMicrotask()
等
注意:
- 在
async/await
中,视为同步代码(await上面和右边),在主任务栈里执行。但await
前后会有区分,看第2条说明- 执行到
async
函数时,await上面和右边的内容会在主任务栈里执行,await右边和下面的内容,会在Promise有返回结果时,加入到微任务中开始执行- Promise对象里的代码,是同步执行的,只有
then
回调是微任务。- 调用
then
之前,会先将Promise内部的代码执行完才会执行到then。或者说必须是执行到了resolve()
才可以。await
是会阻塞后面的代码执行,必须等到promise
的结果resolve()
(类似于第4条then的执行顺序)
主任务栈, 宏任务队列,微任务队列,他们三个的执行顺序:
- 先执行主任务栈
- 宏任务队列开始前,需要先把微任务队列清空
- 宏任务开始后,是加入到主任务栈中执行,视为主任务,所以中间有宏/微任务的话,继续添加到对应的队列中等待即可
- 最后执行微任务队列。
- 宏/微任务队列都是先加入的先执行
四、异常处理
<script>
function foo() {
console.log("foo function1")
throw new Error("我是错误信息")
console.log("foo function2")
console.log("foo function3")
console.log("foo function4")
}
function test() {
// 自己捕获了异常的话, 那么异常就不会传递给浏览器, 那么后续的代码可以正常执行
try {
foo()
console.log("try后续的代码")
} catch(error) {
console.log("catch中的代码")
// console.log(error)
} finally {
console.log("finally代码")
}
}
test()
console.log("--------")
</script>
注意:
throw
抛出异常信息new Error("自定义错误信息")
生成异常信息try/catch/finally
接收异常
五、防抖和节流
防抖:只有在某个时间内,没有再次触发某个函数时,才真正的调用这个函数;
(等待最后一次才进行函数调用)
function debounce(fn, delay){
let timerId = null
return function(){
const context = this
//如果接到订单就再等3分钟
if(timerId){window.clearTimeout(timerId)}
//3分钟没有接到订单就直接配送
timerId = setTimeout(()=>{
fn.apply(context, arguments)
timerId = null
},delay)
}
}
节流:在某个时间内(比如500ms),某个函数只能被触发一次;
(按照一定的频率进行调用)
function throttle(fn, delay){
// 设置一个触发开关
let canUse = true
return function(){
//如果为true,就触发技能,否则就不能触发
if(canUse){
fn.apply(this, arguments)
//触发技能后,关闭开关
canUse = false
//在3秒后打开开关
setTimeout(()=>{canUse = true}, delay)
}
}
}
更多推荐
所有评论(0)