promise
- Promise 是一个构造函数
- Promise.prototype 上有 .then 和 .catch 方法
- Promise 表示异步操作
const p = new Promise() 表示创建了一个形式上的 异步操作 因为不知道是什么具体的异步操作。
具体的异步操作 写在 Promise(function(){})中。比如 读文件 就是一个异步操作
const p = new Promise(function(){
fs.readFile('文件1路径', ' utf-8 ', function(err , data){
if(err){
console.log(err.message)
}
else{
console.log(data)
}
})
})
众所周知,异步操作返回的最终结果是没有固定顺序的,是按照哪个执行快哪个先返回结果
const p = new Promise(function(){ fs.readFile('文件1路径'), 'utf-8', function(){...} }) //文件1 内容是 111
const p2 = new Promise(function(){ fs.readFile('文件2路径'), 'utf-8', function(){...} }) //文件2 内容是 222
const p3 = new Promise(function(){ fs.readFile('文件3路径'), 'utf-8', function(){...} }) //文件3 内容是 333
就像上面的代码一样,最终输出的结果 不一定是 111-222-333,也有可能是 111-333-222 等等 三种内容打乱顺序输出。因为读文件 是异步操作
那么我要一些异步操作返回的结果按照一定的顺序执行怎么办呢?比如让文件内容按照 111-222-333 顺序返回
const p = new Promise(function(){
fs.readFile('文件1路径'', ,function(err, data){
if (err) {}
else{
console.log(data);
fs.readFile('文件2路径'',,function(err,data){
if (err) {}
else{
console.log(data);
fs.readFile('文件3路径'',,function(err,data){...}
}
})
}
})
})
可以在第一个文件成功读取后的回调函数中 读取第二个文件 在第二个文件成功读取后的回调函数中 读取第三个文件。这样就可以按照顺序读出 111-222-333 了
但是这样那么多 函数嵌套 在这么大一段代码中 极其难看 且 不易维护 ,我突然想调换一下文件内容顺序 还要重新 调整 大段代码 。
那么怎么办呢?
.then 和 .catch
其实在Promise 中的 function 函数中两个有两个参数 ,这两个参数分别是 读取文件成功后的回调函数 successCallback 还有 读取文件失败后的回调函数 errorCallback
const p = new Promise(function (successCallback, errorCallback){
fs.readFile('文件路径','utf-8',function(err,data){
if(err){
errorCallback(err.message)
}
else{
successCallback(data)
}
})
})
这两个 回调函数 暂时 是没有内容的,Promise 对象 拥有 .then 和 .catch 方法, 可以用来定义 successCallback 和 errorCallback 回调函数内容
- then(function( ){ } , function ( ) { }) 对应 successCallback , errorCallback
- catch( function( ){ } ) 对应 errorCallback
我们先把这个 读文件的 异步操作 封装 成一个函数 以备调用 方便
function getContentFile( fpath ){
const p = new Promise(function(successCallback, errorCallback){
fs.readFile(fpath,'utf-8', function(err,data){
if(err){
successCallback(err.message)
}
else{
errorCallback(data)
}
})
})
}
我们需要 这个 getContentFile( ) 函数 返回一个 Promise 对象 我们才能使用 .then 和 . catch 方法。 所以我们 return new Promise()
function getContentFlie( fpath ){
return new Promise(function(successCallback, errorCallback){...})
}
在来调用这个 getContentFile 函数
var p = getContentFile('文件1路径') //返回的是一个 promise 对象
p.then(function(data){
console.log(data)
return getContentFile('文件2路径') //返回的是一个 promise对象这样就可以继续调用 then 方法
}).then(function (data){
console.log(data)
return getContentFile('文件3 路径')
}).then(function (data){
console.log(data)
}).catch(function (err) {
console.log(err.message)
})//最后在末尾添加 catch 方法 来统一 定义失败回调函数 内容
这样相对于 前面的回调函数 代码简洁多了 但是只是相对于前面的代码来说.
可我还是觉得很丑难维护怎么说?
await 和 async
这时候就轮到 await 和 async 出场了 , 这两个是修饰符. 使用他俩 直接简化 .then 操作. 可以直接拿来用 不用在 .then
await 只能用在被 async 修饰的方法中
如果 某个方法的返回值是 Promise 实例对象,那么 就可以用 await 关键字 ,来修饰 promise 实例
先把上面封装好的读文件 异步操作 拿下来
//返回 promise 对象
function getContextFile (fpath){
return new Promise(function (successCallback, errorCallback){
fs.readFile(fpath,'utf-8',function (err, data){
if (err) { return errorCallback(err.message); }
else{ return successCallback(data); }
})
})
}
//await 修饰异步操作 , async 修饰 包含 await修饰异步操作 的方法
async function test(){
const data1 = await getContextFile('文件1 路径')
//修饰完后的getContextFile 使 data1 拿到 成功读取 文件1 的内容, 不用在 data1.then 来设置回调函数
console.log(data1)
}
test()
调用一下 test 函数, 这样是可以输出文件1 的内容的 牛不牛
当然要是遇到读取失败怎么办.直接在后面加上 catch 方法
async function test(){
const data1 = await getContextFile('文件1 路径').catch(function (err){return err})
if(data1 instanceof Error){
console.log('读取文件失败')
}else{
console.log(data)
}
}
按照顺序来的话 直接在 test 函数 中 按照顺序 多来调用 几次 getContextFile 就行
async function test(){
const data1 = await getContextFile('文件1 路径') ....
console.log(data1)
const data2 = await getContextFile('文件2 路径') ....
console.log(data2)
const data2 = await getContextFile('文件3 路径') ....
console.log(data3)
}
test() //输出结果 111 222 333
异步操作不能按顺序 输出. 这样使得 异步操作 像 非异步操作一样 按照顺序输出.
axios
axios 是用来发起 AJAX 请求的 发起AJAX请求也是异步的, axios.get 和 axios.post 返回的 是 promise 对象
Getinfo(){
const result = axios.get('http://www.liulongbin.top:3005/api/get')
result.then(function(res){
console.log(res)
})
}
// 上面这么写太麻烦了 简化一下。 axios.get 返回的是一个promise 对象 就可以用 await 来修饰,用了 await 来修饰异步操作, 那么就得用 async 来修饰函数。
// 我们要的只是请求回来对象中 的一个 data 属性。利用 axios 请求回来的 promise 对象自带 6个属性。
// 其实我们最终要拿到的是其中 data 属性(解放 data 属性)中的data。可以利用 解构赋值
// 例如
// car{
// name:'奥迪',
// number:1111
// }
// const { name, number } = car
// console.log(name); //输出了 奥迪
// 给name起个别名就是
// const { name: carname ,number}
async Getinfo(){
const { data:res } = await axios.get('接口')
console.log(res.data);
}