异步

单线程

  1. 何为单线程?

只有一个线程,只能做一件事,只关注一件事

// 循环运行期间,JS 执行和 DOM 渲染暂时卡顿
var i,
  sum = 0
for (i = 0; i < 10000000; i++) {
  sum += i
}
console.log(sum)

// alert 不处理,JS 执行和 DOM 渲染暂时卡顿
console.log(1)
alert('hello')
console.log(2)
1
2
3
4
5
6
7
8
9
10
11
12
  1. 出现的原因: 避免 DOM 渲染的冲突
  • 浏览器需要渲染 DOM
  • JS 可以修改 DOM 结构
  • JS 执行的时候,浏览器 DOM 渲染会暂停
  • 两段 JS 也不能同时执行(都修改 DOM 就冲突了)
  • webworker 支持多线程,但是不能访问 DOM
  1. 解决方案: 异步
console.log(100)
setTimeout(function() {
  console.log(200)
}, 1000)
console.log(300)
console.log(400)
1
2
3
4
5
6
  1. 前期异步带来的问题

(1) 没按照书写方式执行,可读性差

(2) callback 中不容易模块化

event-loop (事件轮询)

(1) 事件轮询,JS 实现异步的具体解决方案

(2) 同步代码,直接执行

(3) 异步函数先放在 异步队列 中

(4) 待同步函数执行完毕,轮询执行 异步队列 的函数

jquery Deferred

jQuery 1.5 的变化

  • 无法改变 JS 异步和单线程的本质
  • 只能从写法上杜绝 callback 这种形式
  • 它是一种语法糖形式,但是解耦了代码
  • 很好的体现:开放封闭原则
// jq 1.5 之前
var ajax = $.ajax({
  url: 'data.json',
  success: function() {
    console.log('success1')
    console.log('success2')
    console.log('success3')
  },
  error: function() {
    console.log('error')
  }
})
console.log(ajax) // 返回一个 XHR 对象

// jq 1.5 之后
var ajax = $.ajax('data.json')
ajax
  .done(function() {
    console.log('success 1')
  })
  .fail(function() {
    console.log('error')
  })
  .done(function() {
    console.log('success 2')
  })
console.log(ajax) // 返回一个 deferred 对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

Promise 标准

  • 异常捕获
// 规定:then 只接受一个参数,最后统一用 catch 捕获异常
result
  .then(function(img) {
    console.log(img.width)
  })
  .then(function(img) {
    console.log(img.height)
  })
  .catch(function(ex) {
    // 最后统一 catch
    console.log(ex)
  })
1
2
3
4
5
6
7
8
9
10
11
12
  • 多个串联
var src1 = ''
var result1 = loadImg(src1)
var src2 = ''
var result2 = loadImg(src2)

// 链式操作
result1
  .then(function(img) {
    console.log('第一个图片加载完成')
    return result2
  })
  .then(function(img) {
    console.log('第二个图片加载完成')
  })
  .catch(function(ex) {
    // 最后统一 catch
    console.log(ex)
  })
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  • Promise.all & Promise.race
// Promise.all 接受一个 promise 对象的数组
// 待全部完成之后,统一执行 success
Promise.all([result1, result2]).then(datas => {
  // 接受到的 datas 是一个数组,依次包含了多个 Promise 返回的内容
  console.log(datas[0])
  console.log(datas[1])
})

// Promise.rece 接受一个包含多个 Promise 对象的数组
// 只要有一个完成,就执行 success
Promise.race([result1, result2]).then(data => {
  //data 即最先执行完成的 Promise 的返回值
  console.log(data)
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  • 状态变化

(1) 三种状态: pending fulfilled rejected

(2) 初始状态 pending

(3) pending 变成 fulfilled,或者 pending 变成 rejected

(4) 状态变化不可逆

  • then

(1) Promise 实例必须实现 then 这个方法

(2) then() 必须可以接收两个函数作为参数

(3) then() 返回的必须是一个 Promise 实例

async/await 的使用

  • 介绍

(1) then 只是讲 callback 拆分了

var w = waitHandle()
w.then(
  function() {
    console.log('ok 1')
  },
  function() {
    console.log('err 1')
  }
).then(
  function() {
    console.log('ok 2')
  },
  function() {
    console.log('err 2')
  }
)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

(2) async/await 是直接的同步写法

const load = async function() {
  const result1 = await loadImg(src1)
  console.log(result1)
  const result2 = await loadImg(src2)
  console.log(result2)
}
load()
1
2
3
4
5
6
7
  • 用法

(1) 使用 await,函数必须用 async 标示 (2) await 后面跟的是一个 Promise 实例 (3) 需要 babel-polyfill

JS 当前异步的解决方案

  • jQuery Deferred
  • Promise
  • async/await
上次更新: 10/25/2018, 10:02:15 PM