同步异步概念
同步(Synchronous)
- 代码会阻塞
异步(Asynchronous)
-
代码不会阻塞,不知道何时收到请求
-
异步代码没法return返回值
-
通过回调函数获取返回值,但是会存在回调地狱问题
JS为单线程的语言
回调函数方式接收异步代码的结果
function foo(count, successCallback, failureCallback) {
// 异步任务
setTimeout(() => {
if (count > 0) {
count++
// 将成功结果传入回调函数successCallback
successCallback(count)
} else {
failureCallback('count<0')
}
}, 3000)
}
foo(99, (res) => {
console.log('count值为:', res);
}, (err) => {
console.log('错误提示:', err);
})
//3s后打印
//count值为: 100
Promise方式接收异步代码的结果
function foo(count) {
return new Promise((resolve, reject) => {
// 异步任务
setTimeout(() => {
if (count > 0) {
count++
// 将成功结果传入回调函数resolve
resolve(count)
} else {
reject('count<0')
}
}, 3000)
})
}
foo(-99).then(res => {
console.log('count值为:', res);
}).catch(err => {
console.log('错误提示:', err);
})
//3s后打印
//count值为: 100
promise
promise概念
promise为一个对象,存取异步调用的结果
回调函数的嵌套写法,promise将其简化为链式编程
Promise中维护了两个隐藏属性:
- PromiseValue,用来存储数据
- PromiseStatus,记录Promise的状态
- pending 进行中
- fulfilled 完成。执行了resolve回调,触发then回调函数
- rejected 拒绝。执行了reject回调,触发catch回调函数
resolve/reject传参
resolve(val)
-
val为基本类型、引用类型
-
val为新的Promise对象,取决于新的Promise对象
const newP = new Promise((resolve, reject) => { // resolve('newP resolved') reject('newP rejected') }) const p = new Promise((resolve, reject) => { resolve(newP) }) p.then(res => { console.log(res); }).catch(err => { console.log(err); }) //newP rejected
-
val为thenable,取决于then的回调函数
const p = new Promise((resolve, reject) => { resolve(1) }) p.then(res => { console.log('then1:', res); return { then: function (resolve) { resolve(2) } } }).then(res => { console.log('then2:', res); }) //then1: 1 //then2: 2
reject(val)
val任意类型,都会直接传递到catch
then/catch执行时机
创建promise对象后,自动调用回调函数(resolve, reject)=>{}
每个then catch方法都返回promise对象
-
手动return、抛出异常 返回结果分别被链式中最近的then、catch拿到
-
没有手动return、抛出异常 返回undefined
const p = new Promise((resolve, reject) => {
resolve(1)
})
p.then(res => {
console.log('then1:', res);
}).then(res => {
console.log('then2:', res);
return 2
}).catch(err => {
console.log('catch1:', err);
}).then(res => {
console.log('then3:', res);
throw new Error('出错了')
}).catch(err => {
console.log('catch2:', err);
})
p.then(res => {
console.log('then11:', res);
})
//结果
then1: 1
then11: 1
then2: undefined
then3: 2
catch2: Error: 出错了
// 创建promise对象后,自动调用回调函数
const promise = new Promise((resolve, reject) => {
// resolve('111')
reject('111')
})
// 第一个回调函数取出
promise.then((result) => {
console.log(result);
}, (reason) => {
console.log(reason);
})
promise.catch((reason) => {
console.log(reason);
})
promise.finally(() => {
console.log("成功与否都他妈执行");
})
Promise.resolve().then(() => { //Promise.resolve()返回resolved状态,触发then回调
console.log(1); //打印1 返回resolved转态,触发then回调
}).catch(() => {
console.log(2);
}).then(() => { // 打印3 整体返回resolved状态
console.log(3);
})
//1
//3
Promise.resolve().then(() => { //打印1 返回rejected状态 触发catch回调
console.log(1);
throw new Error('erro1')
}).catch(() => { //打印2 返回resolved状态 触发then回调
console.log(2);
}).catch(() => {
console.log(3);
})
//1
//2
//sum返回一个promise对象,则sum为异步函数
function sum(a, b) {
// promise处理异步代码
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(a + b)
}, 1000);
})
}
// promise解决回调地狱的方式
// promise对象调用then catch finally方法都会返回promise对象
sum(1, 2)
//第一个then拿到sum中promise对象的resolve存储的值
.then(result => {
return result + 3
//第二个then上一个then的返回值
}).then(result => {
return result + 4
}).then(result => {
console.log(result);
})
//输出
//10
Promise静态方法
//1.将Promise对象设置为fulfilled
Promise.resolve()
//2.将Promise对象设置为rejected
Promise.reject()
//3.then所有Promise对象都为fulfilled
// catch最快的rejected状态
//输出:[val1,val2,...]
Promise.all([p1,p2,...])
//4.then所有Promise对象都有状态(不论状态fulfilled/rejected)
//输出:对象数组
Promise.allSettled([p1,p2,...])
//5.then最快的fulfilled状态
// catch最快的rejected状态
// 注:fulfilled、rejected状态一起比
Promise.race([p1,p2,...])
//6.then最快的fulfilled状态
// catch所有Promise对象都为rejected状态
// 注:fulfilled状态一起比
Promise.any([p1,p2,...])
宏任务微任务
微任务队列:Promise、async/await、Object.observe、Proxy
-
new Promise((resolve, reject) => {…})
new Promise的回调函数(resolve, reject) => {…}是同步的立即执行
then catch finally方法的回调函数进入微任务队列
-
await下面的代码相当于then回调里的代码,放入微任务队列
宏任务队列:定时器,延时器,Ajax,浏览器帧循环requestAnimationFrame
- setTimeout(fn,t),时间t之后,回调函数fn进入宏任务队列
执行流程(执行每一个宏任务之前都先执行完微任务队列)
- 调用栈(主线程)中的代码
- 微任务队列的所有任务
- DOM监听、UI渲染
- 宏任务队列的所有任务
async与await
以同步的方式,书写异步代码
- async函数返回值
- 普通值,包裹到Promise.resolve中
- 新的Promise,状态由新Promise决定
- thenable,状态由返回对象的then方法决定
- await只能用于 async声明的异步函数中,或es模块的顶级作用域中
- await下面的代码相当于then回调里的代码,放入微任务队列
async function fn(){
// async函数返回promise对象
// 100 会包装为promise对象
return 100
}
(async function(){
const a = fn()
// Promise {<fulfilled>: 100}
console.log(a);
// await下面的代码相当于then回调里的代码
const b = await fn()
// 100
console.log(b);
})()