js逆向基础13异步编程2

上一节课只有微任务队列

new Promise(()=>{})//参数需要一个参数也就是回调函数

promise.then方法会生成一个微队列,如果说promise是一个完成态的promise的话,

promise.then 生成一个微队列
就会把.then的第一个参数(第一个回调函数)放到微队列中,等待执行,如果promise是拒绝态的话就会把.then方法里的第二个参数(第二个回调函数),放到微队列中,等待执行。

根据even loop循环的执行流程,setTimeout会形成一个宏任务

宏0任务从上往下依次执行
在同一个宏任务中比如说宏0任务中遇到setTimerout会把它放到宏1,遇到第二个setTmierout会排到宏1的下一轮也就是宏2,而在宏0中遇到第一个微任务会变成微0,遇到第二个就会排在微0后面也就是微0里第一个微任务执行完就去执行遇到的第二个微任务。

Promise结合setTimeout

console.log('start')
setTimeout(() => {
console.log('time')
})
Promise.resolve().then(() => {
console.log('resolve')
})
console.log('end')
这段代码开始执行会发生什么呢?(最开始的同步执行代码可以当成宏0 )
最开始会执行script的宏任务,可以理解为是html页面中的script标签,也可以理解为一次性在控制台输入的内容也可以理解成script,script作为一个入口是个宏任务,也就是常说的同步任务的开始
这段代码会优先打印出start,接下来遇到了setTimeout方法没有延迟直接触发,正常来讲有延迟,来控制几秒后会触发,setTimeout会放到宏任务队列中,注意它的宏任务并不是script宏任务,也不是同步任务,我们可以把这个console.log('time')任务叫宏1任务,script是宏0任务,宏0任务执行完成之后会检测是否有微队列任务,如果说script宏0任务执行完成之后,微任务里的内容也执行完了,它才会执行下一个宏任务也就是宏1任务console.log('time'),然后遇到Promise.resolve()会生成一个pr1成功态的对象,然后遇到.then方法会生成一个新的对象p1是pengding,然后把() => {
console.log('resolve')}这个回调函数放到微队列中之后去,再去执行console.log('end')打印出end,这个时候宏0任务也就是script任务执行完毕,宏0任务也就是script任务执行完毕后去检查这一轮微队列中的微任务是否执行完毕,没有执行完毕就会去执行微队列中的微任务打印出resolve,微队列中的微任务执行完成后这一轮的也就是宏0,微0全部执行完成,这个时候由于console.log('resolve')微队列中微任务执行完成,并且没有报错,这个时候调用.then那一瞬间出现的promise也就是p1从pending状态转化成完成态,然后微队列中东西彻底执行完成后,再去执行下一轮宏任务队列中的宏任务也就是宏1.
 




  刚开始整个脚本作为一个宏任务来执行,对于同步代码直接压入执行栈进行执行,因此先打印出    start和end。
 setTimout作为一个宏任务被放入宏任务队列(下一个)
 Promise.then作为一个微任务被放入微任务队列
 本次宏任务执行完,检查微任务,发现Promise.then,执行它
 接下来进入下一个宏任务,发现setTimeout,执行。
 

const promise = new Promise((resolve, reject) => {
console.log(1);
setTimeout(() => {
console.log("timerStart");
resolve("success");
console.log("timerEnd");
}, 0);
console.log(2);
});
promise.then((res) => {
console.log(res);
});
console.log(4);

从上至下,先遇到new Promise,执行该构造函数中的代码1
然后碰到了定时器,将这个定时器中的函数放到下一个宏任务的延迟队列中等待执行
执行同步代码2
跳出promise函数,遇到promise.then,但其状态还是为pending,这里理解为先不执行
执行同步代码4
一轮循环过后,进入第二次宏任务,发现延迟队列中有setTimeout定时器,执行它
首先执行timerStart,然后遇到了resolve,将promise的状态改为resolved且保存结果并将之前的promise.then推入微任务队列
继续执行同步代码timerEnd
宏任务全部执行完毕,查找微任务队列,发现promise.then这个微任务,执行它。

看下面的区别
setTimeout(() => {
console.log('timer1');
setTimeout(() => {
console.log('timer3')
}, 0)
}, 0)
setTimeout(() => {
console.log('timer2')
}, 0)
console.log('start')


setTimeout(() => {
console.log('timer1');
Promise.resolve().then(() => {
console.log('promise')
})
}, 0)
setTimeout(() => {
console.log('timer2')
}, 0)
console.log('start')

下边那个可以猜测其机制为:当宏任务执行过程中产生微任务的时候,会直接轮询微任务。换句话说,宏任务队列中产生的微任务会在当前宏任务完成后立即执行
也可以理解为 setTimeout会独立启用一个宏任务队列,而不是去排队

加点难度
Promise.resolve().then(() => {
console.log('promise1');
const timer2 = setTimeout(() => {
console.log('timer2')
}, 0)
});
const timer1 = setTimeout(() => {
console.log('timer1')
Promise.resolve().then(() => {
console.log('promise2')
})
}, 0)
console.log('start');

刚开始整个脚本作为第一次宏任务来执行,我们将它标记为宏1,从上至下执行
遇到Promise.resolve().then这个微任务,将then中的内容加入第一次的微任务队列标记为微1
遇到定时器timer1,将它加入下一次宏任务的延迟列表,标记为宏2,等待执行(先不管里面是什么内容)
执行宏1中的同步代码start
第一次宏任务(宏1)执行完毕,检查第一次的微任务队列(微1),发现有一个promise.then这个微任务需要执行
执行打印出微1中同步代码promise1,然后发现定时器timer2,将它加入宏2的后面,标记为宏3
第一次微任务队列(微1)执行完毕,执行第二次宏任务(宏2),首先执行同步代码timer1
然后遇到了promise2这个微任务,将它加入此次循环的微任务队列,标记为微2
宏2中没有同步代码可执行了,查找本次循环的微任务队列(微2),发现了promise2,执行它
第二轮执行完毕,执行宏3,打印出timer2

继续加难度
Promise.resolve().then(() => {
console.log('promise1');
const timer2 = setTimeout(() => {
console.log('timer2')
}, 0)
});
const timer1 = setTimeout(() => {
console.log('timer1')
Promise.resolve().then(() => {
console.log('promise2')
})
}, 0)
Promise.resolve().then(() => {
console.log('promise3');
const timer3 = setTimeout(() => {
console.log('timer3')
Promise.resolve().then(() => {console.log('promise4')})
}, 0);
const timer4 = setTimeout(() => {
console.log('timer4')
}, 0);
});
console.log('start');

所以我们可以理解为: Promise.resolve().then 产生的微任务会进入一轮队列,而不会进入下一轮

const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success')
}, 1000) // 注意这个延时
})
const promise2 = promise1.then(() => {
throw new Error('error!!!')
})
console.log('promise1', promise1)
console.log('promise2', promise2)
setTimeout(() => {
console.log('promise1', promise1)
console.log('promise2', promise2)
}, 2000)

无论什么时候遇到.then就会在一瞬间生成一个promise
微任务中只要报错就会变成拒绝态

 稍微加深一点点,综合一点点
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("success");
console.log("timer1");
}, 1000);
console.log("promise1里的内容");
});
const promise2 = promise1.then(() => {
throw new Error("error!!!");
});
console.log("promise1", promise1);
console.log("promise2", promise2);
setTimeout(() => {
console.log("timer2");
console.log("promise1", promise1);
console.log("promise2", promise2);
}, 2000);

// 思考:把上边的 2000改成 1000,输出结果会有变化么。 会,也不会~
// 思考:把上边的 1000改成 0,输出结果会有变化么。


 

setTimeout 折磨暂时结束,下面讲解 Promise中的then、catch、finally


const promise = new Promise((resolve, reject) => {
resolve("success1");
reject("error");
resolve("success2");
});
promise
.then(res => {
console.log("then: ", res);
}).catch(err => {
console.log("catch: ", err);
})

A+规范: 一旦promise状态从P转变成 F/R,状态就不会再次被改变

 

let P1 = Promise.reject().then(()=>{})
console.log(P1)
let P2 = Promise.resolve().then(undefined,()=>{console.log(1)})
console.log(P2)
let P3 = Promise.reject().then(()=>{}, ()=>{})
console.log(P3)

R状态的promise如果没有第二个参数,就会返回R状态,如果有第二个参数就会返回F状态

F状态的promise如果没有第一个参数,就会返回F状态

const promise = new Promise((resolve, reject) => {
reject("error");
resolve("success2");
});
promise
.then(res => {
console.log("then1: ", res);
}).then(res => {
console.log("then2: ", res);
}).catch(err => {
console.log("catch: ", err);
}).then(res => {
console.log("then3: ", res);
})

catch可以捕捉到任何时候上层还没有捕捉的错误

那么是否也可以这样理解, .then 实际上是包含错误捕捉功能的, .then 的第二个参数实际上就是 catch~

Promise.resolve(1)
.then(res => {
console.log(res);
return 2;
})
.catch(err => {
return 3;
})
.then(res => {
console.log(res);
});

即使 catch没有捕捉到错误,它也会正常返回一个 F版本的promise,并且参数会正常的进行传递

Promise.resolve('success').then().then().then((res)=>{console.log(res)}).then((res)=>{console.log(res)})

Promise.resolve('success').then(()=>{}).then().then((res)=>{console.log(res)}).then((res)=>{console.log(res)})

也就是说,一旦resolve的值被接收一次之后,那第二次就接收不到了

Promise.resolve().then(() => {
new Error('error!!!')
}).then(res => {
console.log("then: ", res)
}).catch(err => {
console.log("catch: ", err)
})

Promise.resolve().then(() => {
throw new Error('error!!!')
}).then(res => {
console.log("then: ", res)
}).catch(err => {
console.log("catch: ", err)
})


Promise.resolve(1)
.then(2)
.then(Promise.resolve(3))
.then(console.log)

// .then期望的是一个回调函数,如果不是函数,则会发生透传。一直透到console.log这个函数。至于为什么会打印出1

const promise = Promise.resolve().then(() => {
return promise;
})
promise.catch()
// A+ 规范,then 不能返回其本身,否则报错。 这两句话都报错,但是promise的返回值还是可以接收到的
// 这也再次印证了我们的观点: promise.then出现的一瞬间,就会出现一个新的promise而不会去管.then的回调函数的内容

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值