单线程和异步
JS 是单线程语言,只能同时做一件事
浏览器和 nodejs 已支持 JS 启动进程,如 Web Worker
JS 和 DOM 渲染共用同一个线程,因为 JS 可修改 DOM 结构
遇到等待(网络请求,定时任务)不能卡住
需要异步
回调 callback 函数形式
异步和同步的区别
异步不会阻塞代码执行
// 异步 通过(callback 回调函数)执行
console.log(100)
setTimeout(() => {
console.log(200)
}, 1000)
console.log(300)
同步会阻塞代码执行
// 同步
console.log(100)
alert(200)
console.log(300)
异步的应用场景
网络请求
ajax
// ajax
console.log('start')
$.get('./data.json', function(data) {
console.log(data)
})
console.log('end')
图片加载
// 图片加载
console.log('start')
let img = document.createElement('img')
img.onload = function() {
console.log('onload')
}
img.src = '/xx.png'
console.log('end')
定时任务
// setTimeout
console.log(100)
setTimeout(function() {
console.log(200)
}, 1000)
console.log(300)
// setInterval
console.log(100)
setInterval(function() {
console.log(200)
}, 1000)
console.log(300)
promise
主要是用来解决回调地狱的问题,所以出现了promise 。现在主流的方法是使用async 和 await 来进行解决异步问题。 async 和 await 本质上是一个语法糖 使函数的返回值包含在promise中返回。
回调地狱
嵌套格式
$.get(url1, (data1) => {
console.log(data1)
$.get(url2, (data2) => {
console.log(data2)
$.get(url3, (data3) => {
console.log(data3)
// ...
})
})
})
promise
管道格式
function getData(url) {
return new Promise((resolve, reject) => {
$.ajax({
url,
success(data) {
resolve(data)
},
error(err) {
reject(err)
}
})
})
}
const url1 = '/data1.json'
const url2 = '/data2.json'
const url3 = '/data3.json'
getData(url1).then(data1 => {
console.log(data1)
return getData(url2)
}).then(data2 => {
console.log(data2)
return getData(url3)
}).then(data3 => {
console.log(data3)
}).catch(err => console.log(err))
promise加载图片
如果在 then 中 return 一个普通对象,下一个then中函数的参数会接收到;
如果在 then 中 return 一个Promise实例的话,下一个then 中函数接收到的参数就是新 Promise 的 resovle 的参数
function loadImg(src) {
const p = new Promise(
(resolve, reject) => {
const img = document.createElement('img')
img.onload = () => {
resolve(img)
}
img.onerror = () => {
const err = new Error(`图片加载失败 ${src}`)
reject(err)
}
img.src = src
}
)
return p
}
// const url = 'https://img1.baidu.com/it/u=681100297,1255002990&fm=253&fmt=auto&app=120&f=JPEG?w=890&h=500'
// loadImg(url).then(img => {
// console.log(img.width)
// return img
// }).then(img => {
// console.log(img.height)
// }).catch(ex => console.error(ex))
const url1 = 'https://img1.baidu.com/it/u=681100297,1255002990&fm=253&fmt=auto&app=120&f=JPEG?w=890&h=500'
const url2 = 'https://img2.baidu.com/it/u=2412886502,2778604333&fm=11&fmt=auto&gp=0.jpg'
loadImg(url1).then(img1 => {
console.log(img1.width)
return img1 // 普通对象
}).then(img1 => {
console.log(img1.height)
return loadImg(url2) // promise 实例
}).then(img2 => {
console.log(img2.width)
return img2
}).then(img2 => {
console.log(img2.height)
}).catch(ex => console.error(ex))
三种状态
1.pending
2.resloved
3.rejected
状态变化:
pending-> resloved 或者 pending->rejected
状态的变化是不可逆的
状态的表现:
1.pending状态:不会触发then或catch
2.resolved状态:会触发后续的then回调函数
3.rejected状态:会触发后续的catch回调函数
then和catch改变状态:
1.then正常返回resolved,里面有报错则返回rejected
2.catch正常返回resolved,里面有报错则返回rejected
// then() 一般正常返回 resolved 状态的 promise
Promise.resolve().then(() => {
return 100
})
// then() 里抛出错误,会返回 rejected 状态的 promise
Promise.resolve().then(() => {
throw new Error('err')
})
// catch() 不抛出错误,会返回 resolved 状态的 promise
Promise.reject().catch(() => {
console.error('catch some error')
})
// catch() 抛出错误,会返回 rejected 状态的 promise
Promise.reject().catch(() => {
console.error('catch some error')
throw new Error('err')
})