异步代码和同步代码执行顺序
同步代码优先于异步代码执行
例如:
setTimeout(()=>{
console.log(1)
},0)
console.log(2)
// 输出结果: 2 1
用回调函数接收异步代码的返回值
异步代码中retrun 没有意义,例如
function fn() {
setTimeout(() => {
return 1
}, 0)
// 没有返回值,等效于return undefined
}
console.log(fn())//undefined
所以,可以用回调函数接收异步代码的返回值,例如
function fn(callback) {
setTimeout(() => {
callback(1) //执行回调函数
}, 0)
}
fn((data)=>{
console.log(data)//得到数据
})
将回调函数作为对象的属性
将异步函数以对象的形式,传到存在异步代码的函数中,方便接受多种情况下的返回结果,例如
function ajax(options) {
setTimeout(() => {
options.success(1) //执行失败的回调
// options.fail(404) //执行成功的回调
}, 0)
}
ajax({
success(data){
console.log(data)
},
fail(error){
console.log(error)
}
})
回调地狱的形成
如果多个请求存在前后次序的调用问题,代码上的多层嵌套会形成回调地狱
function ajax(options) {
setTimeout(() => {
options.success(1)
}, 0)
}
ajax({
url: '/url1',
success(data1){
ajax({
url: '/url2',
success(data2){
ajax({
url: '/url3',
success(data3){
}
})
}
})
}
})
使用Promise解决回调地狱的问题
Promise的语法
let p = new Promise((reslove, reject)=>{
setTimeout(() => {
// reslove(1) //成功的回调
reject(404) //失败的回调
}, 0)
})
p.then((data)=>{
//接收成功回调的数据
console.log(data)
}).catch((error)=>{
//接收失败的回调的数据
console.log(error)
})
理解Promose的写法
最简单的手写Promise
//定义Promise构造函数
function Promise(fn){
setTimeout(() => {
fn(this.success,this.fail)
}, 0)
}
//注册成功的回调函数
Promise.prototype.then = function(success) {
this.success = success
return this
}
//注册失败的回调函数
Promise.prototype.catch = function(fail) {
this.fail = fail
return this
}
延伸阅读
BAT前端经典面试问题:史上最最最详细的手写Promise教程
解决回调地狱
function axios () {
return new Promise((reslove, reject)=>{
setTimeout(() => {
reslove(1)
}, 0)
})
}
//错误示范,依然存在回调地狱
axios({
url: '/url1'
}).then((data1)=>{
axios({
url: '/url2'
}).then((data2)=>{
axios({
url: '/url3'
}).then((data3)=>{
})
})
})
//正确示范,利用链式调用解决回调地狱
axios({
url: 'url1'
}).then((data1)=>{
return axios({
url: 'url2'
})
}).then((data2)=>{
return axios({
url: 'url3'
})
}).then((data3)=>{
console.log(data3)
})
使用异步函数简化Promise的接收
async function fn () {
let data1 = await axios({url: 'url1'})
let data2 = await axios({url: 'url2'})
let data3 = await axios({url: 'url3'})
}
Javascript代码运行机制
什么是EventLoop?
JavaScript 主线程从“任务队列”中读取异步,任务的回调函数,放到执行栈中依次执行。这个过程是循环不断的,所以整个的这种运行机制又称为 EventLoop(事件循环)。
面试题
//1.异步代码,交给浏览器或nodejs
//1.1执行完成-放到任务队列
setTimeout(() => {
console.log('A')
}, 0)
//2.主线程执行同步代码
for (let i = 0; i < 1000; i++) {
console.log(i)
}
//3.到任务队列取异步结果
//A-最后面
宏任务和微任务
面试题
优先级:同步代码>异步代码(微任务>宏任务) 执行结果:1 3 5 3 2
console.log(1)//同步代码
setTimeout(() => {
console.log(2)//异步代码,宏任务
}, 0)
let p = new Promise((reslove)=>{
console.log(3)//同步代码,微任务
reslove()
})
p.then(()=>{
console.log('4')//异步代码,微任务
})
console.log(5)//同步代码