同步模式

由于JavaScript是单线程,因此JavaScript代码会自上而下执行代码

  • 如果其中有耗时操作,那么就会阻塞程序执行,使得界面卡死

异步模式

异步任务不会等待执行结束再执行下面的代码,代码执行顺序会比较跳跃

  1. console.log("global start")
  2. setTimeout(function timer1() {
  3. console.log("timer1 invoke")
  4. },1800)
  5. setTimeout(function timer2() {
  6. console.log("timer2 invoke")
  7. setTimeout(function inner() {
  8. console.log("inner invoke")
  9. },1000)
  10. },1000)
  11. console.log("global end")
  12. // 执行结果
  13. global start
  14. global end
  15. timer2 invoke
  16. timer1 invoke
  17. inner invoke
  • 首先JavaScript会自上而下执行,遇到settimeout时候将其放在异步线程中倒计时,所有同步代码都自上而下执行,因此会先执行console打印global start 和 global end
  • 然后定时器执行结束之后会将里面的代码推入异步队列,事件循环中执行,因此timer2先打印,time2里面定时器又被搁置一边,事件循环继续将timer1推入主栈中执行
  • 最后inner定时器将里面代码推入异步队列,异步队列推送主栈中执行

JavaScript异步机制.png

同步或异步指的是运行环境所提供的API是同步还是异步模式执行的

回调函数

调用者定义函数传递给执行者执行,其实就是调用者告诉执行者异步任务结算书后应该做什么

  1. function foo (callback) {
  2. setTimeout(function () {
  3. callback()
  4. },3000)
  5. }
  6. foo(function () {
  7. console.log("这就是一个回调函数")
  8. })

Promise

用来解决回调函数嵌套过多的问题,承诺执行异步任务,成功之后做什么,失败后怎么办都是事先定义好的 分为三个状态:pending,resolve,reject

  • 基本用法 ```javascript const promise = new Promise((resolve, reject)=>{ resolve(100) // 承诺成功 })

promise.then(value => { console.log(“resolved”,value) }, error => { console.log(“rejected”, error) })

  1. - 案例
  2. ```javascript
  3. function ajax (url) {
  4. return new Promise(function (resolve, reject) => {
  5. var xhr = new XMLHttpRequest()
  6. xhr.open("get", url)
  7. xhr.responseType = 'json'
  8. xhr.onload = function () {
  9. if(this.status === 200){
  10. resolve(this.response)
  11. } else {
  12. reject(new Error(this.statusText))
  13. }
  14. }
  15. xhr.send()
  16. })
  17. }
  • 常见误区
    • 如果发送多次请求,每次请求都依赖上一个请求的返回结果,写法不注意也会出现promise嵌套过多的情况出现
  • 链式调用

    promise.then会返回一个全新的promise形成promise链 then当中promise是什么状态,下一个then就会帮忙处理这个状态

  1. Promise.then(val=>{
  2. return Promise.resolve(val)
  3. }).then(val=>{
  4. return Promise.reject(val)
  5. }).then(val=>{
  6. return Promise.resolve(val)
  7. },err=>{
  8. console.log(err)
  9. }).then(val => {
  10. return "123"
  11. }).then(val => {
  12. //这个val就是"123"
  13. }).then()
  • 总结
    • Promise对象的then方法会返回一个全新的promise对象
    • 后面的then方法就是在为上一个then返回的Promise注册回调
    • 前面then方法中回调函数的返回值回作为后面then方法回调的参数
    • 如果回调中返回的是Promise,那后面then方法的回调会等待它的结束
      • 异常处理

        可以使用catch注册失败回调,给promise链使用 catch可以捕获所有上面Promise出现过的异常

  1. ajax()
  2. .then(res=>{
  3. })
  4. .catch(err => {
  5. })
  • 全局注册(不推荐)
    1. Promise.on('unhandledRejection',(reason, promise) => {
    2. console.log(reason, promise)
    3. // reason指的是出现失败的原因,一般是一个错误对象
    4. // promise是指出现异常的Promise对象
    5. })
  • 静态方法
    • Promise.resolve ```javascript Promise.resolve(‘foo’) .then( val => { console.log(val) })

// Promise.resolve包裹一个promise得到的promise与包裹的promise是同一个 let promise = ajax(“/api/users”) let promise2 = Promise.resolve(promise) console.log(promise === promise2) // true

Promise.resolve({ then(onFulfilled, onRejected) { //实现了一个thenable onFulfilled(“foo”) } }).then(val => { console.log(val) // foo })

  1. - Promise.reject
  2. ```javascript
  3. Promise.reject('anything')
  4. .catch( err => {
  5. console.log(err)
  6. })
  • Promise并行执行
    • Promise.all

      会等待所有异步任务执行结束

  1. var promise = Promise.all([
  2. ajax("/api/users"),
  3. ajax('/api/login')
  4. ])
  5. promise.then( res => {
  6. console.log(res)
  7. }).catch(err => {
  8. console.log(err)
  9. })
  10. // 都成功才会走then 只要有一个失败都会走catch
  • Promise.race()

    只会等待第一个结束的任务

  1. const request = ajax('/api/posts')
  2. const timeOut = new Promise((resolve, reject) => {
  3. setTimeout(() => reject(new Error('timeout')), 5000)
  4. })
  5. Promise.race([request, timeOut])
  6. .then(val => {
  7. console.log(val)
  8. })
  9. .catch(err => {
  10. console.log(err)
  11. })
  12. // 如果5秒内请求没响应就会直接结束,走到catch
  • Promise 执行时序/宏任务,微任务 ```javascript console.log(“global start”)

setTimeout(() => { console.log(‘settimeout’) },0)

Promise.resolve() .then(() => { console.log(“promise”) }) .then(() => { console.log(“promise 2”) }) .then(() => { console.log(“promise 3”) })

console.log(“global end”)

// 执行结果 global start global end promise promise 2 promise 3 settimeout

  1. > 回调队列的任务称为**宏任务**,宏任务执行过程中可以临时加上一些额外的需求
  2. > 对于这些额外的需求,可以选择作为一个**新的宏任务**进入到队列中排队
  3. > 也可以作为当前任务的**微任务**,直接在当前任务结束过后立即执行
  4. > 微任务目的提高整体响应能力
  5. - 微任务:
  1. Promise
    1. MutationObserver
    2. node中的process.nextTick ```

Generater 异步方案

  1. function * foo () {
  2. console.log('start')
  3. try {
  4. const res = yield 'foo'
  5. console.log(res) // bar
  6. } catch (e) {
  7. console.log(e) // Generator error
  8. }
  9. }
  10. const generator = foo()
  11. const result = generator.next()
  12. console.log(result) // foo
  13. generator.next("bar")
  14. generator.throw(new Error('Generator error'))

Async / Await 语法糖

  1. async function main () {
  2. let res = await ajax('/api/users')
  3. }
  4. const promise = main()
  5. promise.then( () => {
  6. console.log('all completed')
  7. })