• 同步API
    • 连续的执行,就叫做同步【js】同步和异步知识总结
      • 连续执行,不能插入其他任务,所以操作系统从硬盘读取文件的这段时间,程序只能干等着。
    • 同步API:只有当前API执行完成后,才能继续执行下一个API【js】同步和异步知识总结
    • 前一个任务结束后再执行后一个任务,程序的执行顺序与任务的排列顺序是一致的、同步的。
    • 同步任务都在主线程上执行,形成一个执行栈。
  • 异步API
    • 所谓"异步",简单说就是一个任务分成两段,先执行第一段,然后转而执行其他任务,等做好了准备,再回过头执行第二段。
    • 比如,有一个任务是读取文件进行处理,异步的执行过程就是下面这样。【js】同步和异步知识总结
      • 任务的第一段是向操作系统发出请求,要求读取文件。
      • 然后,程序执行其他任务,等到操作系统返回文件,再接着执行任务的第二段(处理文件)
    • 这种不连续的执行,就叫做异步。
    • 异步API:当前API的执行不会阻塞后续代码的执行【js】同步和异步知识总结
    • JS 的异步是通过回调函数实现的。
    • 异步任务相关回调函数添加到任务队列中(任务队列也称为消息队列)。
    • 一般而言,异步任务有以下三种类型:
      • 1、普通事件,如click、resize等
      • 2、资源加载,如load、error等
      • 3、定时器,包括setinterval、setTimeout等
  • js执行机制【js】同步和异步知识总结
    • 1.先执行,执行栈中的同步任务
      • 当遇到异步任务,将其放入回调函数队列中,继续执行下面的同步任务
    • 2.异步任务(回调函数),异步进程处理,将其放入回调函数队列中
    • 3.一旦执行栈中的所有同步任务执行完毕,系统就会按次序读取回调函数队列中的异步任务,于是被读取的异步任务结束等待状态,进入执行栈,开始执行。
      • 执行栈中同步任务执行完后,将回调函数队列中的异步任务放入,执行栈最下方开始执行
    • 异步进程处理【js】同步和异步知识总结
      • 在主线程任务栈,遇到异步任务,会将其提交给异步代码执行区,当异步任务被触发后,异步进程处理会将其提交个回调函数队列
      • 当主线程任务栈中同步任务执行完后,将回调函数队列中的异步任务放入,执行栈最下方开始执行
      • 当将放入执行栈的异步任务也执行完后,主线程还会去任务队列查看是否还有任务可执行
    • 事件循环
      • 由于主线程不断的重复获得任务、执行任务、再获取任务、再执行,所以这种机制被称为事件循环(eventloop)。
  • 回调函数
    • JavaScript 语言对异步编程的实现,就是回调函数。
    • 所谓回调函数,就是把任务的第二段单独写在一个函数里面,等到重新执行这个任务的时候,就直接调用这个函数。
    • 比如:读取文件进行处理,是这样写的【js】同步和异步知识总结
      • readFile 函数的第二个参数,就是回调函数,也就是任务的第二段。
      • 等到操作系统返回了 /etc/passwd 这个文件以后,回调函数才会执行。
    • 回调函数的作用就是,将异步代码写在一个块级作用域中,当其中的异步函数执行后,才会调用回调函数,这时异步函数已经执行完成,所以调用的回调函数中代码可以依次执行【js】同步和异步知识总结
      • 通过在函数形参中拿到的回调函数引用地址,可以调用回调函数并传递参数给回调函数的形参,这样回调函数就可以获得被调用函数中的信息
  • Promise
    • 回调地狱
      • 回调函数本身并没有问题,它的问题出现在多个回调函数嵌套
      • 比如:假定读取A文件之后,再读取B文件,代码如下。【js】同步和异步知识总结
        • 不难想象,如果依次读取多个文件,就会出现多重嵌套。代码不是纵向发展,而是横向发展,很快就会乱成一团,无法管理。这种情况就称为“回调地狱”(callback hell)。
    • Promise就是为了解决这个问题而提出的。
      • 在ES6中提供了Promise,它不是新的语法功能,而是一种新的写法,允许将回调函数的横向加载,改成纵向加载。
    • 语法【js】同步和异步知识总结
      • Promise实际上是一个构造函数,所以需要先使用new关键字创建实例
    • 参数
      • Promise的构造函数接收一个函数的参数,此函数有两个参数:resolve , reject,分别表示异步操作执行成功和异步执行失败的后的回调函数。【js】同步和异步知识总结
        • resolve
          • resolve是将Promise的状态置为fullfiled,fullfiled状态将触发then方法
          • 异步操作执行成功可以使用resolve带回一个实参
          • resolve实际上是一个回调函数,可以将数据作为实参传递出异步API
          • Promise对象调用then方法,then接收一个函数参数,并且会拿到Promise执行成功回调resolve函数的参数。
            • 就相当于回调函数带回异步API中数据
        • reject
          • reject是将Promise的状态置为rejected,rejected状态将触发catch方法
          • 异步操作执行失败可以使用reject带回一个实参
          • reject实际上是一个回调函数,可以将数据作为实参传递出异步API
          • Promise对象调用catch方法,catch接收一个函数参数,并且会拿到Promise执行成功回调 reject函数的参数。
            • 就相当于回调函数带回异步API中数据
    • Promise方法
      • Promise 提供了 .then(onFulfilled, onRejected) 和 .catch(onRejected) 方法用于注册监听 Promise 对象的状态变更。
      • Promise对象调用then方法,then接收一个函数参数,并且会拿到Promise执行成功回调resolve函数的参数。
        • then()方法是异步执行。
        • 意思是:就是当.then()前的方法执行完后再执行then()内部的程序,这样就避免了,数据没获取到等的问题。
        • 语法
          • promise.then([onFulfilled][, onRejected])
          • 其中onFulfilled,就是resolve状态的回调函数,用于指定发生错误时的回调函数
          • onRejected就是reject
        • 就相当于回调函数带回异步API中数据
        • 参数
          • 1. 如果参数是 Promise 实例,那么 promise.resolve 将不做任何修改、原封不动地返回这个实例。
          • 2. 如果参数是一个 thenable 对象。
            • thenable 对象指的是具有 then 方法的对象
            • 比如:【js】同步和异步知识总结
            • Promise.resolve 方法会将这个对象转为 Promise 对象,然后就立即执行thenable对象的then方法。
          • 3. 如果参数是一个原始值,或者是一个不具有then方法的对象,则 Promise.resolve 方法返回一个新的 Promise 对象,状态为 resolved。
            • 比如:下面代码生成一个新的 Promise 对象的实例p。【js】同步和异步知识总结
              • 由于字符串 Hello 不属于异步操作(判断方法是字符串对象不具有 then 方法),返回 Promise 实例的状态从一生成就是 resolved,所以回调函数会立即执行。
              • Promise.resolve 方法的参数,会同时传给回调函数。
          • 4. Promise.resolve 方法允许调用时不带参数,直接返回一个 resolved 状态的 Promise 对象。
            • 需要注意的是,立即 resolve() 的 Promise 对象,是在本轮“事件循环”(event loop)的结束时执行,而不是在下一轮“事件循环”的开始时。【js】同步和异步知识总结
        • 返回值【js】同步和异步知识总结
          • 返回了一个值,那么 then 返回的 Promise 将会成为接受状态,并且将返回的值作为接受状态的回调函数的参数值。
          • 没有返回任何值,那么 then 返回的 Promise 将会成为接受状态,并且该接受状态的回调函数的参数值为 undefined。
          • 返回一个已经是接受状态的 Promise,那么 then 返回的 Promise 也会成为接受状态,并且将那个 Promise 的接受状态的回调函数的参数值作为该被返回的Promise的接受状态回调函数的参数值。
          • 返回一个已经是拒绝状态的 Promise,那么 then 返回的 Promise 也会成为拒绝状态,并且将那个 Promise 的拒绝状态的回调函数的参数值作为该被返回的Promise的拒绝状态回调函数的参数值。
          • 返回一个未定状态(pending)的 Promise,那么 then 返回 Promise 的状态也是未定的,并且它的终态与那个 Promise 的终态相同;同时,它变为终态时调用的回调函数参数与那个 Promise 变为终态时的回调函数的参数是相同的。
      • Promise对象调用catch方法,catch接收一个函数参数,并且会拿到Promise执行成功回调 reject函数的参数。
        • .catch() 等价于 .then(null, onRejected),用于指定发生错误时的回调函数
        • 语法
          • promise.catch(error => console.log(error); // 失败了
        • 就相当于回调函数带回异步API中数据【js】同步和异步知识总结
    • Promise实际上就是在原本的异步API中包裹一层函数,其中Promise参数函数的resolve , reject两个参数,实际上和普通的回调函数一样,都接受一个回调函数作为实参,而在运行时返回一个实参给调用他的then或catch方法,这样就会获得异步API中的执行结果
    • 我们可以把任意一个异步操作过程包裹进 Promise 的回调函数体里面,当异步操作成功或失败时分别调用 resolve(value) 或 reject(error) 变更 Promise 对象的状态,这样就成功地把任意形式的异步操作状态转换为格式统一的 Promise 状态。
      • 实例化的 promise 对象维护着一个状态,resolve() 和 reject() 则是用于触发 promise 变更的开关。
    • Promise能把原来的回调写法分离出来,在异步操作执行完后,用链式调用的方式执行回调函数。
      • Promise相对于普通的回调函数(callback)来说从从表面上来说可以简化层层回调的写法,Promise的精髓是“状态”,用维护状态、传递状态的方式来使得回调函数能够及时调用,它比传递callback函数要简单、灵活的多。
    • 控制Promise的执行顺序
      • 使用Promise虽然可以将异步API的执行结果传递出来,但是无法控制异步API的执行顺序
      • 只是new了一个对象,并没有调用它,我们传进去的函数就已经执行了
      • 所以我们用Promise的时候一般是包在一个函数中,在需要的时候去运行这个函数【js】同步和异步知识总结
        • 在Promise的外面再嵌套一层函数,就可以实现控制Promise的执行
    • Promise的链式编程
      • Promise只是能够简化层层回调的写法,而实质上,Promise的精髓是“状态”,用维护状态、传递状态的方式来使得回调函数能够及时调用,它比传递callback函数要简单、灵活的多。
      • Promise 的链式调用是通过 .then() 和 .catch() 方法实现的,其中 .catch() 等价于 .then(null, onRejected),因此我们在接下来的内容当中只需研究 .then() 方法的性质即可。
      • .then() 方法除了用于注册监听函数之外,本身也会创建并返回一个 Promise 对象,这个 Promise 对象用于表征回调函数的执行情况。
        • 当回调函数执行成功时(内部的resolve函数调用) Promise 状态将变更为 'fulfilled',执行过程抛出异常 (内部的rejected函数调用)Promise 状态则变成 'rejected'
      • 透传
        • 在链式调用过程当中,假如某个环节的 Promise 不存在相应状态的监听回调函数,那么这个 Promise 的状态将会往下透传【js】同步和异步知识总结
          • .then 或者 .catch 的参数期望是函数,传入非函数则会发生值穿透
        • 即,Promise中回调函数执行,却没有相应的then()或catch()处理,所以会将上一个 Promise 的状态持续透传了下去。
      • Promise 值传递
        • .then() 方法会将回调函数的执行结果(then中回调函数的return)记录下来,并作为下一个 onFulfilled (resolve成功状态)回调的参数将其传递下去
          • 由于回调函数可以返回任何结果,甚至返回一个 Promise 对象也是可行的。
        • 回调函数所抛出的错误将作为下一个 onRejected 的参数传递下去
  • Generator函数
    • 协程思想
      • 传统的编程语言,早有异步编程的解决方案(其实是多任务的解决方案),其中有一种叫做“携程”(coroutine),意思是多个线程互相协作,完成异步任务。
      • 协程有点像函数,又有点像线程。它的运行流程大致如下:
        • 第一步,协程A开始执行。
        • 第二步,协程A执行到一半,进入暂停,执行权转移到协程B。
        • 第三步,(一段时间后)协程B交还执行权。
        • 第四步,协程A恢复执行。
      • 上面流程的协程A,就是异步任务,因为它分成两段(或多段)执行。
      • 举例来说,读取文件的协程写法如下:【js】同步和异步知识总结
        • 上面代码的函数 asyncJob 是一个协程,它的奥妙就在其中的 yield 命令。
        • 它表示执行到此处,执行权将交给其他协程,也就是说,yield命令是异步两个阶段的分界线。
        • 协程遇到 yield 命令就暂停,等到执行权返回,再从暂停的地方继续往后执行,它的最大优点,就是代码的写法非常像同步操作,如果去除yield命令,简直一模一样。
    • 概念
      • Generator 函数是协程在 ES6 的实现,最大特点就是可以交出函数的执行权(即暂停执行)
      • 下面代码就是一个 Generator 函数。它不同于普通函数,是可以暂停执行的,所以函数名之前要加星号,以示区别。【js】同步和异步知识总结
    • 语法
      • Generator(生成器)是一类特殊的函数,跟普通函数声明时的区别是function后加了一个*号【js】同步和异步知识总结
      • 整个 Generator 函数就是一个封装的异步任务,或者说是异步任务的容器,异步操作需要暂停的地方,都用 yield 语句注明
    • 返回值
      • 调用 Generator 函数,会返回一个内部指针(即遍历器 ),即执行它不会返回结果,返回的是指针对象【js】同步和异步知识总结
        • 上面代码中,调用 Generator 函数,会返回一个内部指针(遍历器)g 
      • 调用指针 的 next 方法,会移动内部指针(即执行异步任务的下一个yield 语句),指向下一个遇到的 yield 语句
      • next 方法的作用是分阶段执行 Generator 函数
        • 每次调用 next 方法,会返回一个对象,表示当前阶段的信息( value 属性和 done 属性)。
        • value 属性是 yield 语句后面表达式的值,表示当前阶段的值;
        • done 属性是一个布尔值,表示 Generator 函数是否执行完毕,即是否还有下一个阶段。
      • next()会比yield多了一个
        • 进行实例化之后,Generator函数里的代码不会主动执行。
        • 第一个next()永远是用于启动生成器,生成器启动后要想运行到最后,其内部的每个yield都会对应一个next(),所以说next()永远都会比yield多一个了
    • 消息传递
      • 通过yield ...和next(...)组合使用,可以在生成器的执行过程中构成一个双向消息传递系统。
      • next 方法可以接受参数,这是向 Generator 函数体内输入数据【js】同步和异步知识总结
        • 第一个 next 方法的 value 属性,返回表达式 x + 2 的值(3)。
        • 第二个 next 方法带有参数2,这个参数可以传入 Generator 函数,作为上个阶段异步任务的返回结果,被函数体内的变量 y 接收。
      • 当next(..)执行到yield语句处时会暂停生成器的执行,同时next(...)会得到一个带有value属性的对象,yield语句后面带的值会赋给value(如果yield后面没有值,value就为undefined)。可以将yield ...效果看成跟return ...类似。
      • 当生成器处于暂停状态时,暂停的yield表达式处可以接收下一个启动它的next(...)传进来的值。当next(...)使生成器继续往下执行时,其传入的值会将原来的yield语句替换掉。
    • 异常处理
      • Generator 函数内部还可以部署错误处理代码,捕获函数体外抛出的错误
      • 使用指针对象的 throw 方法抛出的错误,可以被函数体内的 try ... catch 代码块捕获【js】同步和异步知识总结
        • 上面代码的最后一行,Generator 函数体外,使用指针对象的 throw 方法抛出的错误,可以被函数体内的 try ... catch 代码块捕获
  • Generator+Promise实现完美异步
    • 例子:【js】同步和异步知识总结
    • 当多个Promise并发请求时,正确的写法可以更好地提高性能【js】同步和异步知识总结
      • 请求1和2之间不存在依赖关系,是可以同时进行的【js】同步和异步知识总结
  • 异步函数(async和await)
    • ES7中新增加了异步函数的部分
    • 优化了promise中臃肿冗余的部分封装成API
    • 异步函数是异步编程语法的终极解决方案,它可以让我们将异步代码写成同步的形式,让代码不再有回调函数嵌套,使代码变得清晰明了
    • 所谓异步函数,实际上就是在普通函数定义的前面添加 async关键字,这样普通函数就会变成异步函数
    • 语法
      • 在普通函数定义的前面添加 async关键字,将其变成异步函数【js】同步和异步知识总结
    • 返回值
      • 普通函数默认的返回值是undefined,而异步函数的默认返回值是在原有返回值的基础上,包裹了promise对象【js】同步和异步知识总结
      • 在异步函数内部使用return关键字进行结果返回 结果会被包裹的promise对象中 return关键字代替了resolve方法
    • 异步函数返回promise对象可以使用then方法
      • 调用异步函数再链式调用then方法获取异步函数执行结果
      • 异步函数调用then方法,then中的回调函数参数就是异步函数的返回值【js】同步和异步知识总结
    • 抛出异常 throw
      • 在异步函数内部使用throw关键字抛出程序异常
      • 在异步函数中使用throw关键字,可以抛出异常,将错误信息抛出到异步函数外【js】同步和异步知识总结
      • 异步函数返回promise对象可以使用catch方法
        • 调用异步函数再链式调用catch方法获取异步函数执行的错误信息
        • 异步函数调用catch方法,catch中的回调函数参数就是异步函数中抛出异常的信息
      • throw关键字会导致异步函数暂停,不在执行后续代码
    • await关键字
      • await关键字将会拿到promise对象中传递出来的回调参数
      • await关键字只能出现在异步函数中,也就是说,当使用await获取结果的时候可能会出现被迫多次写async的情况
      • await promise 
        • await后面只能写promise对象 写其他类型的API是不可以的
      • 使用await关键字可以让promise对象脱离(起到调用promise对象then方法作用)【js】同步和异步知识总结
      • await 可以暂停异步函数的执行,等待promise对象返回结果后再向下执行后续结果
        • 也就是说,使用await关键字可以有序的让异步函数执行【js】同步和异步知识总结
    • promisify方法
      • 只有异步函数才能使用await,且await必须跟在promise对象前,而原有API并没有返回promise对象
      • promisify方法可以包装现有的异步API函数,将其变为异步函数【js】同步和异步知识总结
      • promisify方法存放在系统模块,util中【js】同步和异步知识总结
      • 语法
        • promisify(要改造的API函数)
        • 注意这里是改造,不是调用,所以参数应该为引用
      • 返回值
        • promisify返回处理好的API函数,即一个返回promise对象的异步函数
  •  

相关文章:

  • 2021-08-30
  • 2021-09-05
  • 2022-01-16
  • 2021-11-20
  • 2021-11-20
  • 2021-04-25
猜你喜欢
  • 2021-12-02
  • 2021-10-05
  • 2021-07-16
  • 2021-05-18
  • 2022-02-07
  • 2021-11-18
相关资源
相似解决方案