同步异步编程+promise全面解析+async/await

同步异步编程

首先,要从进程和线程中说起:
进程:一个程序[浏览器打开一个页面就是开辟一个进程]
线程:程序中具体做事情的
( 一个进程中,会包含一到多个线程)
我们都知道,浏览器是多线程的:

  • GUI渲染线程:渲染页面的
  • JS引擎线程:渲染和解析JS的
  • 时间触发线程:监听DOM事件的触发
  • 定时器触发线程:监听定时器是否到时间
  • 异步HTTP请求线程:从服务器端获取资源信息/数据的
  • WebWorker等等
    然后呢,利用多线程是可以实现“异步编程”的:就是同时做多件事情
    同步编程”:单线程,一次只能处理一件事情,这件事情完成,才能继续处理后面的事情
    JS是单线程的,因为浏览器只会分配一个“JS引擎线程”去渲染JS,所以JS大部分操作都是“同步的”+,但是JS中也一定会有一些“异步”的操作代码。
    注意注意:循环操作是同步编程:如果设置了死循环,当前循环这个事情永远都结束不了,后期所有的其他任务也都无法执行(避免出现死循环)
    我们都知道JS代码是自上而下执行的,因此,浏览器解析的时候也是自上而下,而且遵循的原则是:同步永远先于异步,异步中同等可执行条件下,异步微任务永远先于异步宏任务。
    说到这里,大家肯定会有疑问,异步微任务和宏任务都是什么,怎么区分呢?大家请看下图,这里面包含了常见的异步宏任务和微任务:同步异步编程+promise全面解析+async/await
    代码执行过程:
    @1 自上而下依次解析js代码,同步代码正常执行即可
    @2 如果遇到异步代码,首先将该任务放入webAPI中进行状态监听,如果该任务此时可执行,不直接执行,而是放入EventQuene的可执行队列中去等待执行。
    @2 EventQuene的可执行队列包含微任务和宏任务两个队列,则这时要对该任务进行区分,宏任务和微任务放入这两个队列中。
    @3 然后继续执行下面的代码,等带所有同步代码执行完成后,再去EventQuene的可执行队列中去看,有微任务则拿出来执行,没有可执行的微任务再看可执行的宏任务。
    @4 如果都没有,则继续等待,直至出现可执行的微任务/宏任务,继续按照规则执行,以此类推,直至代码执行结束。
    然后一张代码图肯定就更加明白了

同步异步编程+promise全面解析+async/await

Promise全面解析

  • 概念刨析
    Promise可以说是一个内置类,可以通过new创建promise实例
    let p=new Promise([executor]);
    [executor]:可执行函数
    • new Promise的时候,在promise内部会立即把[executor]函数执行
    • 同时给[executor]函数传递两个值[函数类型]:resolve/reject
    • 内置私有属性
      [[PromiseState]] 实例状态:pending准备状态 fulfilled/resolve成功态 rejected失败态
      [[PromiseResult]] 实例的值
  • 公共属性方法都是存在 Promise.prototype上的 then,catch,finally, Symbol(Symbol.toStringTag):“Promise”
    其中[executor]执行resolve/reject都是为了改变promise实例的状态和值[结果],一旦状态被改变成fulfilled(成功态)/rejected(失败态)就不能再改为其他的状态,如果[executor]函数执行报错,则
    [[PromiseState]]: rejected
    [[PromiseResult]]: 报错
    因为Promise内部做了异常信息捕获利用[try/catch]
  • THEN方法
    不过实例状态的改变,可以控制,执行then方法时,存放的两个方法中的某一个方法执行
    状态成功执行的是:onfulfilledCallback
    状态失败执行的是:onrejectedCallback,并且把[[PromiseResult]]的值传递给方法。
    同时,基于实例.then()执行返回的新实例的状态和值也是受原实例影响的,例如:原实例为p1,新实例为p2,则p2的状态和值取决于以下几个方面:
    P1.THEN存放的onfulfilled或者onrejected不论哪个方法执行
    @1 看返回值 如果返回的是一个全新的promise实例[NEWP]:NEWP的状态和结果直接决定了P2的状态和结果
    @2 如果返回的不是promise实例:只要方法执行不报错,P2就是成功的,方法return的结果就是P2的值。
  • all方法
Promise.all([Promise数组:{要求数组中的每一项尽可能都是promise实例}]):返回一个新的Promise实例AA,
//     AA成功还是失败,取决于数组中的每一个promise实例是成功还是失败,
//     只要有一个是失败,AA就是失败的,只有都成功AA才是成功的片

async+await

我们都知道, async+await是为promise+generator的语法糖,在这里generator是生成器函数,就不做过多解释了,主要还是对async/awai~~t做主要说明:
async:函数修饰符,控制函数返回promise实例

  • 函数内部执行报错,则返回失败的promise实例,值是失败的原因
  • 自己返回一个promise,以自己返回的为主~~
  • 如果函数内部做了异常捕获,则还是成功态
  • 使用async的主要目的:是为了在函数内部使用await
    await: 后面放置一个promise实例[我们书写的不是,浏览器也会把其变为promise实例]
    ① await Promise.resolve(100); 已知实例状态是成功的
    ② await new Promise.resolve((resolve,reject)=>{…});实例转态未知
    ③ await 100; 等价于await Promise.resolve(100);
    ④await func();先把函数执行,把函数执行结果作为Promise实例放在await 后面
  • await会中断函数体中其下面的的代码执行{await表达式会暂停整个async函数的的执行进程并让出其控制权};只有等待await后面的promise实例是成功态以后,才会把之前暂停的代码继续执行,如果后面的promise实例是失败的,则下面的代码就不再执行了
  • await是异步的微任务
  • 函数体中遇到await,后面的代码该咋就咋,但是下面的代码会暂停执行[把他们当做一个任务,放置在EventQuene的微任务队列中]
    如下列例子:
function func1() {
    console.log('func1 start');
    return new Promise(resolve => {
        resolve('OK');
    });
}
function func2() {
    console.log('func2 start');
    return new Promise(resolve => {
        setTimeout(() => {
            resolve('OK');
        }, 10);
    });
}
console.log(1);
setTimeout(async () => {
    console.log(2);
    await func1();
    console.log(3);
}, 20);
for (let i = 0; i < 90000000; i++) {} //循环大约要进行80MS左右
console.log(4);
func1().then(result => {
    console.log(5);
});
func2().then(result => {
    console.log(6);
});
setTimeout(() => {
    console.log(7);
}, 0);
console.log(8);
// 1 4 func1 start func2 start 8 5 2 3 7 6

解析图如下
同步异步编程+promise全面解析+async/await
本期分享就到这里啦,欢迎大家留言讨论~~~&&小屋Niki

上一篇:SpringBoot 如何异步编程,老鸟们都这么玩的


下一篇:【JavaScript】async 函数