先说一下微任务:
微任务队列:
异步任务需要适当的管理。为此,ECMA 标准规定了一个内部队列
PromiseJobs
,通常被称为“微任务队列(microtask queue)”(ES8 术语)
队列(queue)是先进先出的:首先进入队列的任务会首先运行。
只有在 JavaScript 引擎中没有其它任务在运行时,才开始执行任务队列中的任务。
https://zh.javascript.info/microtask-queue
“任务队列”是一个事件的队列(也可以理解成消息的队列),IO设备完成一项任务,就在”任务队列”中添加一个事件,表示相关的异步任务可以进入”执行栈”了。主线程读取”任务队列”,就是读取里面有哪些事件。https://www.ruanyifeng.com/blog/2014/10/event-loop.html
——阮一峰
我的理解:微任务队列其实就是一些事件的傀儡队列,这个傀儡就是回调函数,当主线程任务完成之后,开始读取微任务队列中的事件时,就是去执行事件对应的回调函数。
ps:(可以想象成一个工作狂,他会提前准备一个框框(微任务队列)放一些当前任务中可以慢慢处理的其他任务,然后先去做他当前的主要的工作,做完主要工作就回去检查这个框框,这个框的任务也做完了,就去问老大(宏任务队列)还有没有下一个任务(下一个宏任务))
微任务中也可以有微任务,所以会有无限套娃的风险。https://developer.mozilla.org/zh-CN/docs/Web/API/HTML_DOM_API/Microtask_guide
promise中的then方法:
思否:https://segmentfault.com/q/1010000022578087
我觉得这个答案更符合我的理解:
then的回调函数什么时候进入PromiseJobs取决于then方法前一个promise的状态,
如果调用 then 时 promise 是 pending 状态,回调会进入 promise 的 [[PromiseFulfill/RejectReactions]] 列表里;否则会进入 PromiseJobs。
看例子:
eg1(调用then的promise状态为pending):
new Promise(()=>{}).then((res)=>{console.log("我是then"+res)})
console.log("我是同步的")
输出:
"我是同步的"
结论:如果调用 then 时 promise 是 pending 状态,回调会进入 promise 的[[PromiseFulfill/RejectReactions]] 列表里等待执行;
eg2(调用then的promise状态不为pending):
new Promise((res)=>{res(1)}).then((res)=>{console.log("我是then:"+res)})
console.log("我是同步的")
输出:
"我是同步的"
"我是then:1"
结论:
如果调用 then 时 promise 不是 pending 状态,则会进入 PromiseJobs,待同步任务执行完,则执行PromiseJobs中的任务
eg3:
new Promise((res)=>{}).then(console.log("我是then"))
console.log("我是同步的")
输出:
"我是then"
"我是同步的"
思考:调用then的promise是pending状态,为什么"我是then"还是会打印?👇
eg4:
new Promise((res)=>{res(1)}).then(console.log("我是then"))
console.log("我是同步的")
输出:
"我是then"
"我是同步的"
思考:????为什么还是会打印👇
👇👇👇
-
then方法的参数
then方法接受两个参数(onFulfilled, onRejected)
-
If
onFulfilled
is not a function, it must be ignored. -
If
onRejected
is not a function, it must be ignored. 文档——https://promisesaplus.com/
上面说的很清楚,如果接受的参数不是一个函数,那么必须被忽略(不管他)所以会有值穿透的情况
好,再来看看上面的思考:
new Promise(()=>{}).then(console.log("我是then")) console.log("我是同步的") 首先明确一点:console.log是一个方法,也就是一个函数,所以你再看看你then里面传的是什么,是console.log("xxxxxx"),所以你在这里同步立即执行这个函数,然后把这个函数的返回值传到then里面去,所以相当于你在then里面传了一个值undefined 不信,我们来看看: new Promise((res)=>{res(1)}).then(console.log("我是then")) console.log("我是同步的") 这个输出和上面一样,但是不一样的是,调用then的promise有结果 1 ,且状态不是pending 所以就算中间的then会被忽略,再调用一个正常then还是可以接受到数据 new Promise((res)=>{res(1)}) .then(console.log("我是then")) .then(res=>{console.log("promise的结果:"+res)}) console.log("我是同步的") 输出: "我是then" "我是同步的" "promise的结果:1" 不信再来: new Promise(()=>{}) .then((function(){console.log(2)})())//中间这个then传入一个立即执行的函数效果和上面一样 .then(res=>{console.log(res)}) console.log("我是同步的") 输出: 2 "我是同步的" 好了,到了这里应该都明白了,接下来,看一下then添加回调函数的写法:https://wangdoc.com/javascript/async/promise.html#promiseprototypethen
let func = function() { return new Promise((resolve, reject) => { resolve('我是老大new Promise'); }); }; let cb = function() { return '我是回调函数的返回值'; } // 1. func().then(function () { return cb();//这一句等同于 return '我是回调函数的返回值' }).then(resp => { console.warn(resp); // 输出 '我是回调函数的返回值' console.warn('1 =========<'); }); // 2. func().then(function () { cb();//在这个函数里面只是执行了一下cb函数,但是没有返回任何东西:所以默认返回undefined return undefined }).then(resp => { console.warn(resp);// 输出: undefined console.warn('2 =========<'); }); // 3. func() .then(cb())// 这个then里面传入的相当于是cb函数的返回值 '我是回调函数的返回值',所以发生值穿透 .then(resp => { console.warn(resp); // 值穿透 ——> 输出:'我是老大new Promise' console.warn('3 =========<'); }); // 4. func().then(cb)// 这里的then里面传入的是一个函数,而不是一个值,所以内部会对这个函数进行一个封装,返回'我是回调函数的返回值' .then(resp => { console.warn(resp); //输出:'我是回调函数的返回值' console.warn('4 =========<'); }); 内部封装大致如下:👇👇
.then(new Promise((res,rej)=>{ res(cb()); }))
-
console.log()和console.log是不一样的
then方法内部会进行一个判断:看是否是函数
-
当then里面传入console.log时,相当于传入了一个函数log,于是promise的函数执行器就会帮你调用new Promise(),去调用这个函数,
传入console.log时,在then中相当于发生如下过程 new Promise(res=>res(1)).then(()=>{ return new Promise((res,rej)=>{ res(console.log()); }) })
-
当then里面传入console.log()时,相当于传入了一个非函数,也就是console.log()这个函数的返回值undefined,所以会发生值穿透,所以上面第二种情况,先打印2,再打印new Promise中的res的参数值
-
then的
回调方法
的注册时机(事件机制是先注册再执行)
注册时机其实还是看调用then的promise状态,只要promise状态改变了,其调用的then的方法就会被注册,但是还没有被执,执行再按照注册顺序进行
https://juejin.cn/post/6844903987183894535