普通的函数从上往下执行,遇到异步函数会扔到事件队列中,不会阻止主线程执行后面的代码,JS永远不会卡住。
Promise
要点
- Promise并没有消除回调有then,用async await 消除[then]回调
- 状态:未决状态(unsettled)[pending]已决状态(settled)[fulfilled,rejected]
- Promise的执行器参数,抛出错误之后,Promise会自动变成rejected
- promise的状态一旦确定之后,数据和状态无法改变
- Promise的构造函数回调参数,直接执行
- then方法会返回一个新的Promise,新任务的状态取决于后续的处理
- 若then参数不是函数,没有相关的后续处理函数(对象,数字不是函数),新任务的状态和前任务一致,数据为前任务的数据
- 若有后续处理但还未执行,新任务挂起
- 若后续任务执行了,则根据后续处理的情况确定新任务的状态
- 后续执行无错,新任务的状态为完成,数据为后续处理的返回值
- 后续执行有错,新任务的状态为失败,数据为异常对象
- 后续执行后返回的是一个任务对象,新任务的状态和数据与该任务对象一致
const pro = new Promise((resolve,reject)=>{
console.log(a)
})
console.log(pro)
//:Promise {<rejected>: ReferenceError: a is not defined
// at <anonymous>:2:17
// at new Promise (<anonymous>)
// at <a…}
静态方法
| 方法名 | 含义 |
|---|---|
| Promise.resolve(data) | 直接返回一个完成状态的任务 |
| Promise.reject(data) | 直接返回一个拒绝状态的任务 |
| Promise.all(任务数组) | 返回一个任务 任务数组全部成功则成功 任何一个失败则失败 |
| Promise.any(任务数组) | 返回一个任务 任务数组任一成功则成功 任务全部失败则失败 |
| Promise.allSettled(任务数组) | 返回一个任务 任务数组全部状态已确定则成功 该任务不会失败 |
| Promise.race(任务数组) | 返回一个任务 任务数组任一状态确定则确定,状态和其一致 |
async
要点
async用于修饰函数,被它修饰的函数一定返回Promise
async function m(){
return 123
}
//等于
async function m(){
return new Promise((resolve)=>resolve(123))
}
console.log(m())//promise {123}
//当成promise使用
m().then(res=>console.log(res))//123
async函数返回promise相当于没有标记async
async function m(){
return new Promise((resolve)=>{
setTimeout(()=>{
resolve(123)
},1000)
})
}
async函数内出现错误或者手动thow相当于promise执行reject()
async function m(){
const data = null
data.toString()
return 123
}
cosnole.log(m())//Promise{reject}
//手动reject
async function fune(){
throw new Error(1)
}
console.log(fune)//Promise{reject}
await
要点
表示等待某个Promise完成,必须用于async函数内
function delay(duration){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve()
},duration)
})
}
(async function test(){
await delay(1000)
})()
await等待的不是promise,会将其变成promise
(async()=>{
const data = await 1//await Promise.resolve(1)
})()
(async()=>{
isSuccess = false
for(const name of beatyCirls){
//开始表白
try{
const reply = await sendMessage(name)//表白
console.log(reply)
console.log('表白成功')
isSuccess = true
break;//退出循环
}catch(reply){
console.log(reply)
console.log('表白失败')
}
}
if(!isSuccess)
console.log("注孤生")
})
(async ()=>{
const data = await getHeros()
const result = data.map((d)=>`<li>${d.cname}</li>`).join('')
ul.innerHTML = result
})()
用try catch替代promise的then catch
相关面试题
执行:执行栈 | 宏队列 | 微队列 | promise状态 输出:
题目1
- new Promise创建实例的参数回调直接执行,不进入事件队列
- resolve()确定了promise的状态,不代表函数return,resolve之后的代码仍需执行
- promise.then 进入微队列排队
const promise = new Promise((resolve,reject)=>{
console.log(1)
resolve()//直接修改了promise的状态fulfilled 数据undefined
console.log(2)
})
promise.then(()=>{
console.log(3)
})
console.log(4)
//1 2 4 3
题目2
- promise进入微队列的时机,只有状态改变才会进入微队列
const promise = new Promise((resolve,reject)=>{
console.log(1)
setTimeout(()=>{//settimeout回调被取回执行栈的时候,promise.then才进入微队列
console.log(2)
resolve()//then回调进入微队列
console.log(3)
})
})
promise.then(()=>{
console.log(4)
})
console.log(5)
//1 5 2 3 4
题目3
- Promise链式调用,前面pending后面也是pending
- 前面的状态改成了fulfilled undefine,前面的promise没有后续处理,后面promise的状态和数据继承前面的
- 前面的状态改变了,后续执行无错,后续promise的状态为fulfilled,数据为返回值
const promise1 = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve()
},1000)
})
const promise2 = promise1.catch(()=>{//此回调不执行,没有失败
return 2
})
console.log('promise1',promise1)
console.log('promise2',promise2)
setTimeout(()=>{
console.log('promise1',promise1)
console.log('promise2',promise2)
},2000)
//Promise {pending} Promise {pending}
//Promise {fulfilled undefined} Promise {fulfilled undefined}
===================================
将上述resolve改成reject()
//Promise {pending} Promise {pending}
//Promise {rejected undefined} Promise {fulfilled 2}
题目4
- await后面的代码是放在then,微队列里面的
async function m(){
console.log(0)
const n = await 1;
console.log(n)
}
//等于
//function m(){
// return //Promise.resolve(1).then((n)=>console.log(n))
//}
m()
console.log(2)
// 2 1
题目5
- await 会将后面的函数变成Promise
- async函数返回promise,await后面的代码等里面async那个promise状态改变再执行
- await有一个async函数,await后面的代码=then
async function m(){//1. 声明
console.log(0)
const n = await 1 //状态fulfilled,console.log(1)放进微队列
console.log(n)
}
(async ()=>{
await m()//2. 执行m
console.log(2)
})()
console.log(3)
// 0 3 1 2
题目6
- await 嵌套 啊~ 为什么????
- m2没加await
- async函数全部执行完毕,有返回结果即执行结束
- m3 先执行,输出的前两个是内部打印的m2
- 同步m3 执行m2执行m1,m1的promise最先声明执行并改变状态fulfilled
- m2是async函数,返回的promise状态是pending,因为async内的函数没有执行完毕,所以m3中执行m2返回的状态是pending
相关promise执行及状态改变的过程:
async function m1(){
return 1
}
async function m2(){
const n = await m1()//await Promise.resolve(1) await 1 ,将console.log(1)放入微队列
console.log(n)
return 2
}
async function m3(){//里面没有await,相当于同步
const n = m2()// 没有await
console.log(n)// Promise {pending}
return 3
}
m3().then((n)=>{
console.log(n)
})
m3()
console.log(4)
题目7
- then方法里面传的不是回调函数,then方法返回的promise的状态和数据和前面的promise保持一致
- 传数字,传对象都不是回调函数
- console.log是函数,可以作为回调,then的promise状态fulfilled之后,then的回调会被调用
Promise.resolve(1).then(2).then(Promise.resolve(3)).then(console.log)
题目8
- 变量的赋值其实就是右边表达式执行的过程,因为赋值需要等右边的表达式执行完毕后再赋值
- 所以b是链式then的最后一个Promise {pending}
- a在赋值执行右边表达式的过程中打印a,得到undefined,执行完[同步走一遍]再打印会得到promise {pending}
let a //没赋值 undefined
let b = new Promise((resolve,reject)=>{
console.log('promise1')
setTimeout(()=>{
resolve()
},1000)
}).then(()=>{
console.log('promise2')
}).then(()=>{
console.log('promise3')
}).then(()=>{
console.log('promise4')
})
a = new Promise(async (resolve,reject)=>{
console.log(a)
await b//b是最后一个then的Promise,第一个promise的resolve在宏任务里
console.log(a) //await之后再执行右边的表达式已经执行了,Promise {p}
console.log("after1")
await a //我等待我完成之后再完成我,永不执行
resolve(true)
console.log("after2")
})
console.log("end")
题目9
async function async1(){
console.log('async1 start')
await async2()
console.log('async1 end')
}
async function async2(){
console.log('async2')
}
console.log('script start')
setTimeout(()=>{
console.log('setTimeout')
})
async1()
new Promise(function(resolve){
console.log('promise1')
resolve()
}).then(function(){
console.log('promise2')
})
console.log('script end')
题目10
- 创建node环境的微队列:
setTimeout(function(){
console.log(1)
},0)
process.nextTick(function(){
console.log(2)
})
console.log(3)
//3 2 1
- 创建浏览器环境的微队列
<script>
const p = document.createElement('p')
setTimeout(function () {
console.log(1)
})//默认0
const observer = new MutationObserver(function () {
console.log("变化了")
})
observer.observe(p, {
childList: true//内部所有变化
})
p.innerHTML = '1'
console.log(2)
</script>
//2 变化了 1
- 创建微任务函数
function runMicroTask(callback) {
if (process && process.nextTick) {//node环境
process.nextTick(callback)
} else if (MutationObserver) {//browser环境 需要优化成单例模式
const p = document.createElement('p')
const observer = new MutationObserver(callback)//为了把它放进微队列
observer.observe(p, {
childList: true
})
p.innerHTML = '1'//触发callback直接进入微队列
} else {
setTimeout(callback, 0)
}
}
setTimeout(()=>console.log(1))
runMicroTask(()=>console.log(2))
console.log(3)
Promise实现
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
/**
* 运行一个微队列 把传递的函数放到微队列
* @param {Function} callback
*/
function runMicroTask(callback) {
if (process && process.nextTick) {
process.nextTick(callback)
} else if (MutationObserver) {//需要优化成单例模式
const p = document.createElement('p')
const observer = new MutationObserver(callback)//为了把它放进微队列
observer.observe(p, {
childList: true
})
p.innerHTML = '1'//触发callback直接进入微队列
} else {
setTimeout(callback, 0)
}
}
class MyPromise {
/**
* @param {Function} executor 任务执行器,立即执行
*/
constructor(executor) {
this._state = PENDING
this._value = undefined
this._handles = [];
try {
executor(this._resolve.bind(this), this._reject.bind(this))//立即执行,内部抛出错误,状态改为rejected
} catch (error) {
this.reject(error)
}
}
/**
* 向处理队列中添加函数
* @param {Function} executor 添加的函数
* @param {String} state 该函数什么状态下执行
* @param {Function} resolve 让then函数返回的Promise成功
* @param {Function} reject 让then函数返回的Promise失败
*/
_pushHandles(executor, state, resolve, reject) {
this._handles.push({
executor, state, resolve, reject
})
}
_changeState(newState, value) {
if (this._state !== PENDING) return
this._state = newState
this._value = value
}
_resolve(data) {
this._changeState(FULFILLED, data)
}
_reject(reason) {
this._changeState(REJECTED, reason)
}
/**
*
* @param {Function} onFulfilled
* @param {Function} onRejected
* @returns
*/
then(onFulfilled, onRejected) {
return new Promise((resolve, reject) => {
this._pushHandles(onFulfilled, FULFILLED, resolve, reject)
this._pushHandles(onRejected, REJECTED, resolve, reject)
})
}
}
const pro = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve(123)
console.log(pro)
}, 0);
reject(000)
})
pro.then(function A1(d) { console.log(d) }, function A2(a) { console.log(a) })
pro.then(function B1(d) { console.log(d) }, function B2(a) { console.log(a) })
console.log(pro)