问题导向
Promise是什么? 如何使用?
如果你都有了答案,可以忽略本文章,或去JS学习地图寻找更多答案
Promise是什么
//是什么?
简单说:JS中异步编程的解决方案
从语法上来说:Promise是一个构造函数
从功能上来说:Promise对象用来封装一个异步操作并可以获取其结果
//为什么?
1.指定回调函数的方式更加灵活
回调嵌套:必须在启动异步任务前指定成功或失败的回调函数,才能拿到结果
promise:启动异步任务后,返回promise对象,想拿结果的时候在指定回调
prosemi.then(successCallback, failCallBack)
2.支持链式调用,可以解决回调函数嵌套问题,也就是回调地狱
回调地狱:为了任务的执行顺序
回调地狱的缺点:不便于阅读和异常处理
//如何用?
Promise-API
Promise 构造函数 new Promise(excutor)
excutor函数:执行器 (resolve, reject) => {} //内部同步回调
resolve函数: 成功回调
reject函数: 失败回调
原型方法:
Promise.prototype.then(value => {}, reason => {}) //异步回调
Promise.prototype.catch(err => {}) //then失败回调的语法糖
Promise.prototype.finally(() => {}) //总会执行
静态方法:
Promise.resolve()
Promise.reject()
Promise.all([]) //执行多个任务,有一个失败,就全部失败
Promise.race([]) //执行多个任务,只返回第一个成功的任务
Promise.allSettled([]) //执行多个任务,无论是失败状态还是成功状态,都会以数组对象的方式返回数据
语法糖:
async await + try catch
Promise状态改变
Promise的设计采用三种状态来标记一个任务是成功还是失败,
它不但会保存任务的执行结果,
而且,会根据任务状态进入相应的流程
注意:
一个Promise对象链式调用一次只能改变一次状态,且状态不可逆
三种状态:
new Promise:pending //准备态
resolved //成功态
rejected //失败态
改变状态:
resolve():如果当前是pendding,会变成resolved
reject(): 如果当前是pendding,会变成rejected
抛出异常: 会变成rejected,被catch捕抓
异步回调
两种类型的回调函数
//回调函数
三个条件:
1.自己定义
2.自己不调用
3.最终会执行
如:setTimeout(() => {console.log('回调')}, 1000)
//同步回调
arr.forEach(item => {console.log(item)})
console.log('后执行,因为forEach是同步回调')
//异步回调
setTimeout(() => {console.log('回调')}, 0)
console.log('先执行,因为setTimeout是异步回调')
异步的问题
//异步任务,无法保证执行顺序
fs.readFile('./data/a.txt','utf8',(err,data) => {
if(err) throw err
console.log(data)
})
fs.readFile('./data/b.txt','utf8',(err,data) => {
if(err) throw err
console.log(data)
})
fs.readFile('./data/c.txt','utf8', (err,data) => {
if(err) throw err
console.log(data)
})
//通过回调嵌套的方式来保证顺序
//回调地狱:造成多层嵌套,代码混乱,难以理解
fs.readFile('./data/a.txt','utf8',(err,data) => {
if(err) throw err
console.log(data)
fs.readFile('./data/b.txt','utf8',(err,data) => {
if(err) throw err
console.log(data)
fs.readFile('./data/c.txt','utf8',(err,data) => {
if(err) throw err
console.log(data)
})
})
})
使用promise解决问题
管式代码,容易阅读,错误统一处理
封装
function readFile(path){
return new Promise((resolve,reject) => {
fs.readFile(path,'utf8',(err,data) => {
if(err) {
reject(err)
}
resolve(data)
}
})
}
使用
readFile('./data/a.txt')
.then((data) => {
console.log(data)
return readFile('./data/b.txt')
})
.then((data) => {
console.log(data)
return readFile('./data/c.txt')
})
.then((data) => {
console.log(data)
})
.catch((err) => {
console.log(err)
})
Promise-API详解
then
第一个参数是:成功回调,可写null,只写失败回调
第二个参数是:失败回调,可选
new Promise((resolve,reject) => {
setTimeout(() => {
if (Math.random() * 10 > 5) {
resolve('成功')
}
reject('失败')
}, 1000)
}).then((data) => {
console.log(data)
},(err) => {
console.log(err)
})
catch
可以统一接收错误,放到代码的后面,
如果前面没有错误的处理(then的第二个参数)
就走catch,如果有就走错误的处理(单独处理)
new Promise((resolve,reject) => {
setTimeout(() => {
if (Math.random() * 10 > 5) {
resolve('成功')
}
reject('失败')
}, 1000)
}).then((data) => {
console.log(data)
}).catch((err) => {
console.log(err)
})
finally
无论成功失败都会执行
new Promise((resolve,reject) => {
setTimeout(() => {
if (Math.random() * 10 > 5) {
resolve('成功')
}
reject('失败')
}, 1000)
}).then((data) => {
console.log(data)
}).catch((err) => {
console.log(err)
}).finally(() => {
console.log(‘无论成功失败都会执行’)
})
Promise.reject() :在成功态抛出异常
new Promise(resolve => {
resolve('哈哈哈')
}).then(value => {
if(value !== '成功'){
return Promise.reject('参数错误')
}
console.log(value)
}).catch(error => {
console.log(error)
})
Promise.all
处理多个请求,如果其中有一个是失败状态,Promise.all的状态也会变成失败,就会执行失败逻辑,用来批量处理数据
成功:返回全部promise成功的数组
失败:返回失败的promise
const p1 = new Promise((resolve, reject) => {
if (Math.random() > 0.5) {
resolve('第一个成功')
}
reject('第一个失败')
})
const p2 = new Promise((resolve, reject) => {
if (Math.random() > 0.5) {
resolve('第二个成功')
}
reject('第二个失败')
})
Promise.all([p1, p2])
.then((result) => {
console.log(result)
})
.catch((error) => {
console.log(error)
})
Promise.allSettled
处理多个请求,无论是失败状态还是成功状态,都会以数组对象的方式返回数据
const p1 = new Promise((resolve, reject) => {
if (Math.random() > 0.5) {
resolve('第一个成功')
}
reject('第一个失败')
})
const p2 = new Promise((resolve, reject) => {
if (Math.random() > 0.5) {
resolve('第二个成功')
}
reject('第二个失败')
})
Promise.allSettled([p1, p2])
.then((result) => {
console.log(result)
})
.catch((error) => {
console.log(error)
})
返回结果如下:
[
{status:'fulfilled',value:'第一次成功'},
{status:'rejected',reason:'第二次失败'}
]
//实际业务
const promises = ['大神','乔伊'].map(name => {
return ajax(`xxx${name}`)
})
Promise.allSettled(promises).then(values => {
let users = values.filter(user => {
return user.status === 'fulfilled'
})
console.log(users)
})
Promise.race
处理多个请求,哪个返回快,就用哪个
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('第一个异步')
}, 1000)
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('第二个异步')
}, 200)
})
Promise.race([p1, p2])
.then((result) => {
console.log(result)
})
.catch((error) => {
console.log(error)
})
学习更多