同步模式
由于JavaScript是单线程,因此JavaScript代码会自上而下执行代码
- 如果其中有耗时操作,那么就会阻塞程序执行,使得界面卡死
异步模式
异步任务不会等待执行结束再执行下面的代码,代码执行顺序会比较跳跃
console.log("global start")
setTimeout(function timer1() {
console.log("timer1 invoke")
},1800)
setTimeout(function timer2() {
console.log("timer2 invoke")
setTimeout(function inner() {
console.log("inner invoke")
},1000)
},1000)
console.log("global end")
// 执行结果
global start
global end
timer2 invoke
timer1 invoke
inner invoke
- 首先JavaScript会自上而下执行,遇到settimeout时候将其放在异步线程中倒计时,所有同步代码都自上而下执行,因此会先执行console打印global start 和 global end
- 然后定时器执行结束之后会将里面的代码推入异步队列,事件循环中执行,因此timer2先打印,time2里面定时器又被搁置一边,事件循环继续将timer1推入主栈中执行
- 最后inner定时器将里面代码推入异步队列,异步队列推送主栈中执行
同步或异步指的是运行环境所提供的API是同步还是异步模式执行的
回调函数
调用者定义函数传递给执行者执行,其实就是调用者告诉执行者异步任务结算书后应该做什么
function foo (callback) {
setTimeout(function () {
callback()
},3000)
}
foo(function () {
console.log("这就是一个回调函数")
})
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) })
- 案例
```javascript
function ajax (url) {
return new Promise(function (resolve, reject) => {
var xhr = new XMLHttpRequest()
xhr.open("get", url)
xhr.responseType = 'json'
xhr.onload = function () {
if(this.status === 200){
resolve(this.response)
} else {
reject(new Error(this.statusText))
}
}
xhr.send()
})
}
- 常见误区
- 如果发送多次请求,每次请求都依赖上一个请求的返回结果,写法不注意也会出现promise嵌套过多的情况出现
- 链式调用
promise.then会返回一个全新的promise形成promise链 then当中promise是什么状态,下一个then就会帮忙处理这个状态
Promise.then(val=>{
return Promise.resolve(val)
}).then(val=>{
return Promise.reject(val)
}).then(val=>{
return Promise.resolve(val)
},err=>{
console.log(err)
}).then(val => {
return "123"
}).then(val => {
//这个val就是"123"
}).then()
- 总结
- Promise对象的then方法会返回一个全新的promise对象
- 后面的then方法就是在为上一个then返回的Promise注册回调
- 前面then方法中回调函数的返回值回作为后面then方法回调的参数
- 如果回调中返回的是Promise,那后面then方法的回调会等待它的结束
- 异常处理
可以使用catch注册失败回调,给promise链使用 catch可以捕获所有上面Promise出现过的异常
- 异常处理
ajax()
.then(res=>{
})
.catch(err => {
})
- 全局注册(不推荐)
Promise.on('unhandledRejection',(reason, promise) => {
console.log(reason, promise)
// reason指的是出现失败的原因,一般是一个错误对象
// promise是指出现异常的Promise对象
})
- 静态方法
- 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 })
- Promise.reject
```javascript
Promise.reject('anything')
.catch( err => {
console.log(err)
})
- Promise并行执行
- Promise.all
会等待所有异步任务执行结束
- Promise.all
var promise = Promise.all([
ajax("/api/users"),
ajax('/api/login')
])
promise.then( res => {
console.log(res)
}).catch(err => {
console.log(err)
})
// 都成功才会走then 只要有一个失败都会走catch
- Promise.race()
只会等待第一个结束的任务
const request = ajax('/api/posts')
const timeOut = new Promise((resolve, reject) => {
setTimeout(() => reject(new Error('timeout')), 5000)
})
Promise.race([request, timeOut])
.then(val => {
console.log(val)
})
.catch(err => {
console.log(err)
})
// 如果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
> 回调队列的任务称为**宏任务**,宏任务执行过程中可以临时加上一些额外的需求
> 对于这些额外的需求,可以选择作为一个**新的宏任务**进入到队列中排队
> 也可以作为当前任务的**微任务**,直接在当前任务结束过后立即执行
> 微任务目的提高整体响应能力
- 微任务:
- Promise
- MutationObserver
- node中的process.nextTick ```
Generater 异步方案
function * foo () {
console.log('start')
try {
const res = yield 'foo'
console.log(res) // bar
} catch (e) {
console.log(e) // Generator error
}
}
const generator = foo()
const result = generator.next()
console.log(result) // foo
generator.next("bar")
generator.throw(new Error('Generator error'))
Async / Await 语法糖
async function main () {
let res = await ajax('/api/users')
}
const promise = main()
promise.then( () => {
console.log('all completed')
})