宏任务、微任务

https://juejin.cn/post/6844903999506923528

then里面return或者promise里面return,都相当于resolve功能,不管return的是什么!!!! throw Error后就直接走到catch!!!!

console.log(1)

setTimeout(() => {
    console.log(2)
})

new Promise((resolve, reject) => {
    console.log(3)
    resolve(4)
})
.then((data) => {
    console.log(data)
  return 5
})
.then((data) => {
    console.log(data)
        throw Error('------')
})
.catch((data) => {
    console.log('catch', data)
})

console.log(7)
1、3、7、4、5、catch Error: ------、2

浏览器中promise后面会有.catch和.then,这个也需要考虑

const promise = new Promise((resolve, reject) => {
    console.log(2)
    reject(3)
    console.log(4)
})
  
  promise
  .then(() => console.log(5))
  .catch(() => console.log(6))
  .then(() => console.log(7))
  .catch(() => console.log(8))
  .then(() => console.log(9))
// 结果:2、4、6、7、9

reject的话,就是走catch,然后还会继续往下走then,then里面如果有错,才继续走catch,没错后续的catch就不走了

const promise = new Promise((resolve, reject) => {
    console.log(2)
    reject(3)
    console.log(4)
})
  
  promise
  .then(() => console.log(5))
  .catch(() => console.log(6))
  .then(() => {throw Error('111')})
  .then(() => console.log(7))
  .catch(() => console.log(8))
  .then(() => console.log(9))
// 结果是 2、4、6、8、9,因为有错,直接跳过了他的下一个then,然后直接到了catch,执行完了catch才继续执行的

浏览器中

宏任务和微任务是指异步后,如何将异步函数划分到哪个队列中执行。
正常方法执行,会先从上到下顺序执行方法,这些都属于同步的方法(不包含下面的宏任务和微任务方法的分类。)

setTimeout(_ => console.log(4))

new Promise(resolve => {
  resolve()
  console.log(1)
}).then(_ => {
  console.log(3)
})

console.log(2)
// 这里执行同步的任务为,空的setTimeout方法,之后异步函数塞到宏队列里
// 执行new Promise到then之前的所有方法,把then塞到微队列里
// 在执行console.log(2)

执行顺序: 同步 > 微任务 > 宏任务

每执行一个新的宏任务之前会先去执行微任务队列的信息,直至都清空后,才会执行下一个宏任务(一般应用在宏任务与微任务回调函数中互相又有相应调用的存在时发生)!!!

宏任务分类

宏任务.png

微任务队列

微任务.png

Promise这一段是同步的任务,同理async与Promise相同也是同步任务。只有.then()、catch()、finally()、和await后面的调用才是微任务,(ps:await同行的调用属于同步调用范围,下面的一行才是then函数中的)

详尽举例说明

下面例子中定时器setTimeout的定时都是0,若不是0的话,多个宏任务之前的执行顺序就会有改变,当时间特别短,比如说10ms、20ms等,没办法确定谁先执行,谨记哦!!!

1、在主线程上添加宏任务与微任务

console.log('-------start--------');

setTimeout(() => {
  console.log('setTimeout'); 
}, 0);

new Promise((resolve, reject) => {
    console.log('resolve执行前')
    resolve()
    console.log('resolve执行后,reject执行前')
    reject();
    console.log('reject执行后')
}).then(()=>{
    console.log('Promise实例成功回调执行');
})

console.log('-------e')

从上到下,按步骤走,转换为各队列中执行的方法(队列:先进先出),不是宏任务和微任务的直接放在同步队列里,是宏任务的,把回调函数放到宏队列里,是微任务的,把回调函数放到微任务里

是宏任务的,把回调函数放到宏队列里,是微任务的,把回调函数放到微任务里

// 同步队列
tongbu = [
    console.log('-------start--------'),
    setTimeout,     // 空的,只是一个函数,它的回调函数被放置到了宏队列里,
    // 执行下面的Promise方法,因为当前这段为同步的,不是微任务,后面的then内容放到微队列里
    new Promise((resolve, reject) => {  
      // 内部也属于同步数据,从上到下执行(也可自行转换为同步队列)
        console.log('resolve执行前')
        resolve()
        console.log('resolve执行后,reject执行前')
        reject();
        console.log('reject执行后')
    }),
    console.log('-------e')
]
// 微队列
wei = [
    console.log('Promise实例成功回调执行')
]
// 宏队列
hong = [
    console.log('setTimeout')
]

先执行同步队列,再微队列,最后在执行宏队列,所以得到的结果是

-------start--------
resolve执行前
resolve执行后,reject执行前
reject执行后
-------e
Promise实例成功回调执行
setTimeout

在微任务中创建微任务

后续空的方法就不写了,直接写需要执行的方法

setTimeout(_ => console.log(4))
new Promise(resolve => {
  resolve()
  console.log(1)
}).then(_ => {
  console.log(3)
  Promise.resolve().then(_ => {
    console.log('before timeout')
  }).then(_ => {
    Promise.resolve().then(_ => {
      console.log('also before timeout')
    })
  })
})
console.log(2)

第一步转换,转换为以下的队列

tongbu = [
    resolve => {    // promise
        resolve()
        console.log(1)
    },
    console.log(2)
]
wei = [
    _ => {
        console.log(3)
        Promise.resolve().then(_ => {
          console.log('before timeout')
        }).then(_ => {
          Promise.resolve().then(_ => {
            console.log('also before timeout')
          })
        })
      }
]

hong = [
    _ => console.log(4)
]

在同步队列中获取到结果:1,2
微队列中继续进行转换,由上面已经转换的微队列里进行转换,现在就是转换成同步的执行队列了

// 由上述微队列转换为当前执行的同步队列
tongbu = [
    console.log(3),
]
wei = [
   _ => {
          console.log('before timeout')
        }).then(_ => {
          Promise.resolve().then(_ => {
            console.log('also before timeout')
          })
       }
]

得出同步队列的结果:3
微队列还需要继续转化

// 由上述微队列转换为当前执行的同步队列
tongbu = [
    console.log('before timeout')
]
wei = [
        _ => {
            console.log('also before timeout')
       }
]

最后得到的结果:

1
2
3
before timeout
also before timeout
4
async、await使用例子
setTimeout(_ => console.log(1))

async function async1() {
    console.log('async1 start')
    await async2();
    console.log('async1 end')
}
async function async2() {
    console.log('async2 -1')
    await aa();
    console.log('async2 -2')
    await bb();
}
async function aa () {
    console.log('aa 1')
}
async function bb () {
    console.log('bb1')
}
console.log('async1执行前')
async1();
console.log(6)

转化为以下

tongbu = [
    console.log('async1执行前'),
    () => {
        console.log('async1 start'),
        () => {
            await aa();
            console.log('async2')
            await bb();
        }
    },
    console.log(6)
]
wei = [
    console.log('async1 end')
]
hong = [
    _ => console.log(1)
]

首先能拿到一部分的同步结果,

举一个,两个微任务中创建微任务的详细例子
setTimeout(_ => console.log(1))
new Promise(resolve => {
  resolve()
  console.log('Promise 1')
}).then(_ => {
  console.log('Promise 1 then')
  Promise.resolve().then(_ => {
    console.log('Promise 2 then')
  }).then(_ => {
    Promise.resolve().then(_ => {
        console.log('Promise 3 then')
    })
  })
})
async function async1() {
    console.log('async1 start')
    await async2()
    console.log('async1 end')
}
async function async2() {
    console.log('async2')
}
async1();
console.log(6)

// async1执行前  async1 start  async2 -1  aa 1  6  async2 -2  bb1  async1 end 1

宏任务里创建微任务

setTimeout(() => 微任务方法),ps:函数里返回微任务方法
setTimeout(() => new Promise(resolve => {
  console.log('setTimeout1 start')
  resolve();
  console.log(4)
}).then(_ => {
  console.log(5)
}))
setTimeout(() => new Promise(resolve => {
  console.log('setTimeout2 start')
  resolve();
  console.log(24)
}).then(_ => {
  console.log(25)
}))
new Promise(resolve => {
  resolve()
  console.log(1)
}).then(_ => {
  console.log(3)
})

console.log(2)

// 结果值:1  2  3  setTimeout1 start   4   5   setTimeout2 start   24  25

当多个宏任务时,会先将每个宏任务中的数值都处理完后,才会去做下一个宏任务处理,不管里面是普通的同步任务还是微任务,都要完全处理完一个宏任务,才能处理下一个

setTimeout(微任务方法)

这个时候,相当于setTimeout没有相应的宏任务回调方法!!!! 因为在setTimeout(() => 操作)中,后面的操作才属于宏任务方法,前面的方法属于普通方法,如果前面是微任务方法,那就按微任务方法执行,若前面是同步方法,那就按同步方法逻辑执行

setTimeout(new Promise(resolve => {
  console.log('setTimeout1 start')
  resolve();
  console.log(4)
}).then(_ => {
  console.log(5)
}))
setTimeout(new Promise(resolve => {
  console.log('setTimeout2 start')
  resolve();
  console.log(24)
}).then(_ => {
  console.log(25)
}))
new Promise(resolve => {
  resolve()
  console.log(1)
}).then(_ => {
  console.log(3)
})

console.log(2)

// 结果值:setTimeout1 start   4  setTimeout2 start  24   1   2   5  25  3

因为setTimeout中方法不是()=> 操作信息,这样的返回值,并且内部的方法是微任务方法,所以此时,setTimeout中的方法按照本身方法类型处理,现在他是promise微任务,自上而下顺序里,优先推入微任务队列里,一共有3个微任务,微任务.then之前是同步的,所以直接同步处理,得到上面结果

微任务中添加宏任务

setTimeout(_ => console.log(4))
new Promise(resolve => {
  resolve()
  console.log(1)
}).then(_ => {
  console.log(3)
  Promise.resolve().then(_ => {
    console.log('before timeout')
  }).then(_ => {
    setTimeout(() => {
      console.log('微任务中的宏任务1')
    })
  })
})
new Promise(resolve => {
  resolve()
  console.log(21)
}).then(_ => {
  console.log(23)
  Promise.resolve().then(_ => {
    console.log('before timeout2')
  }).then(_ => {
    setTimeout(() => {
      console.log('微任务中的宏任务2')
    })
  })
})
console.log(2)

// 结果值:
// 1  21  2  3  23  before timeout  before timeout2  4  微任务中的宏任务1  微任务中的宏任务2

按顺序推入微任务队列和宏任务队列中,在前面的会优先处理,因为微任务中的宏任务是后被推入进队列中的,那么就后处理

如果在微任务中的有需要宏任务处理后才能拿到的数据,则先处理当下的宏任务,处理完了,在处理微任务!!!!相当于重新搞了一波写法,就是异步放在setTimeout中执行了!!!

微任务中有宏任务,并且then中的信息需要依赖宏任务处理后才能拿到值,即resolve/reject放在了setTimeout中

setTimeout(() => {
    new Promise((resolve, reject) => {
        console.log(8)
        resolve(9)
    }).then(r => {
        console.log(r)
    })
})
new Promise((resolve, reject) => {
    console.log(1);
    setTimeout(() => {
        console.log(2);
        new Promise((resolve, reject) => {
            console.log(18)
            resolve(19)
        }).then(r => {
            console.log(r)
        })
        
        resolve(3);
    }, 0)
    console.log(4)
  }).then(r => {
    new Promise((re, rj) => {
      setTimeout(() => {
        console.log(5);
      })
      console.log(6);
    })
    console.log(r)
});
  
console.log(7);
setTimeout(() => {
   console.log(10)
})
  
// 1,4,7,8,9,2,18,19,6,3,10,5

先执行同步任务打印出来1、4、7,然后将宏任务、微任务都推入各自的数组中去

hong = [
// 第一个
() => {
    new Promise((resolve, reject) => {
        console.log(8)
        resolve(9)
    }).then(r => {
        console.log(r)
    })
}
// 第二个(微任务的同步模块中的setTimeout)
() => {
        console.log(2);
        new Promise((resolve, reject) => {
            console.log(18)
            resolve(19)
        }).then(r => {
            console.log(r)
        })  
// 相当于在这重新做了一个then的转换!!!!!!!!!!!!!
        new Promise((resolve, reject) => {
            resolve(3);
        }).then(r => {
              new Promise((re, rj) => {
                  setTimeout(() => {
                      console.log(5);
                    })
                  console.log(6);
                  })
                console.log(r)
          })

// 第三个
() => {
   console.log(10)
}
]
wei = [
]

如果Promise.then中的值依赖于setTimeout中的执行结果,那就直接把then方法放在setTimeout中执行,最简化这个数据
参见上面第二个宏任务信息,直接将之前的Promise中的then方法,做一个转换放置在resolve(3)的那个位置上,直接这样得出信息值

node中

宏任务处理不是等前一个宏任务处理完才执行,microtask 会在事件循环的各个阶段之间执行,也就是一个阶段执行完毕,就会去执行 microtask 队列的任务

setTimeout(()=>{
    console.log('timer1')
    Promise.resolve().then(function() {
        console.log('promise1')
    })
}, 0)
setTimeout(()=>{
    console.log('timer2')
    Promise.resolve().then(function() {
        console.log('promise2')
    })
}, 0)
// 结果为: timer1=>timer2=>promise1=>promise2
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,254评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,875评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,682评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,896评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,015评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,152评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,208评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,962评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,388评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,700评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,867评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,551评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,186评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,901评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,689评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,757评论 2 351

推荐阅读更多精彩内容