promise是什么?
Promise
是异步编程的一种解决方案,比传统的解决方案--回调函数和事件--更合理和更强大。它由社区最早提出和实现,ES6将其写进了语言标准,统一了用法,原生提供了Promise对象。
——阮一峰es6教程
本质上 Promise
是一个函数返回的对象,我们可以在它上面绑定回调函数,它代表了一个异步操作的最终完成或者失败。
- 语法上
Promise()
是一个构造函数 - 从功能上来说:promise对象用来封装一个异步操作并可以获取其成功/失败的结果值
promise的作用
支持链式操作,解决回调地狱,让异步代码按照顺序执行
回调地狱是什么?
回调函数嵌套调用(外部回调函数异步执行的结果是嵌套的回调执行的条件)
总结为八个字就是:异步回调,层层嵌套
Promise的三种状态
Promise对象有三种状态
- pending(进行中)
- fulfilled(已成功)
- rejected(已失败)
对象的状态不受外界影响,只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态
promise的状态改变
Promise状态改变只有两种情况
- 从pending(进行中)变为fulfilled(成功)
- 从pending(进行中)变为rejected(失败)
一旦状态改变,就不会再变,任何时候都可以得到这个结果
Promise的使用流程
ES6 规定,Promise对象是一个构造函数,用来生成Promise实例。
- 创建promise实例对象
let p1 = new Promise((resolve,reject)=>{ //你的异步代码 if (/* 异步操作成功 */){ resolve(value); } else { reject(error); } }) /* 参数:回调函数 (resolve,reject)=>{ //你想要的异步操作 } resolve : 完成回调 reject : 回调失败 */
resolve
函数的作用是,将Promise
对象的状态从从 pending
变为 resolved
(成功),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去
reject
函数的作用是,将Promise
对象的状态从 pending
变为 rejected
(失败),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
- 调用实例对象的then方法
p1.then(function(value) { // success }, function(error) { // failure })
then
方法可以接受两个回调函数作为参数。
第一个回调函数是Promise
对象的状态变为resolved
(成功)时调用,第二个回调函数是Promise
对象的状态变为rejected
(失败)时调用。其中,第二个函数是可选的,不一定要提供。这两个函数都接受Promise
对象传出的值作为参数。
举个例子
const fs = require('fs');
//(1)调用Promise构造函数,生成promise实例对象
let p = new Promise( (resolve,reject)=>{
//异步操作: 读取文件a
fs.readFile(`a.txt`, 'utf8', (err, data) => {
if(!err){//成功
/*
(1)resolve:执行then方法里面的第一个函数
*/
resolve(data);
}else{//失败
/*
(1)reject:执行then方法里面的第二个函数
*/
reject(err);
}
});
} );
//(2)调用promise实例的then方法
//第一个参数: 成功的回调
//第二个参数: 失败的回调
p.then(data=>{
console.log(data);
},err=>{
console.log(err);
});
注意 : Promise对象在创建的时候,里面的异步就会立即执行
不要在创建promise的时候处理异步结果,应该调用resolve()或者reject()交给then()方法来处理
解决回调地狱
我们来看一个读取文本内容的例子。
首先创建四个内容不同的文本a、b、c、d,然后创建Promise
实例对象,调用then方法,解决回调地狱
const fs = require('fs');
//Promise是一个构造函数,用于创建promise实例
//(1)调用Promise构造函数,生成promise实例对象
/*
参数:回调函数 (resolve,reject)=>{ //你想要的异步操作 }
resolve : 完成回调
reject : 失败回调
*/
let p1 = new Promise((resolve, reject) => {
//异步操作: 读取文件a
fs.readFile(`a.txt`, 'utf8', (err, data) => {
if (!err) {//成功
/*
(1)resolve:执行then方法里面的第一个函数
(2)resolve底层原理:修改promise状态从pending(进行中)变为fulfilled(成功)
*/
resolve(data);
} else {//失败
/*
(1)reject:执行then方法里面的第二个函数
(2)rreject底层原理:修改promise状态从pending(进行中)变为rejected(失败)
*/
reject(err);
}
});
});
let p2 = new Promise((resolve, reject) => {
//异步操作: 读取文件a
fs.readFile(`b.txt`, 'utf8', (err, data) => {
if (!err) {//成功
resolve(data);
} else {//失败
reject(err);
}
});
});
let p3 = new Promise((resolve, reject) => {
//异步操作: 读取文件a
fs.readFile(`${__dirname}/data/c.txt`, 'utf8', (err, data) => {
if (!err) {//成功
resolve(data);
} else {//失败
reject(err);
}
});
});
let p4 = new Promise((resolve, reject) => {
//异步操作: 读取文件a
fs.readFile(`d.txt`, 'utf8', (err, data) => {
if (!err) {//成功
resolve(data);
} else {//失败
reject(err);
}
});
});
//(2)调用promise实例的then方法
//第一个参数: 成功的回调
//第二个参数: 失败的回调
p1.then(data=>{
console.log(data);
return p2;//在第一个promise的then方法中返回第二个promise对象
})
.then(data=>{//p2的then
console.log(data);
return p3;
})
.then(data=>{//p3的then
console.log(data);
return p4;
})
.then(data=>{//p4的then
console.log(data);
});
// p1.then(data => {
// console.log(data);
// p2.then(data => {
// console.log(data);
// p3.then(data => {
// console.log(data);
// p4.then(data => {
// console.log(data);
// });
// });
// });
// });
promise
解决回调地狱 : 在上一个promise
的then
方法中返回下一个promise
实例对象
总结:promise
本质不是修改异步的顺序(异步永远是无序的),而是通过控制异步结果的顺序,从而实现异步代码有序执行。
Promise解决回调地狱函数封装
以上的代码看起来有些冗余,我们可以通过函数封装的方式使代码变得精简。
const fs = require('fs');
//Promise是一个构造函数,用于创建promise实例
//封装一个创建promise的函数
function createPromise(filename){
return new Promise((resolve,reject)=>{
fs.readFile(`${filename}.txt`, 'utf8', (err, data) => {
if (!err) {//成功
resolve(data);
} else {//失败
reject(err);
}
});
});
};
let p1 = createPromise('a');
let p2 = createPromise('b');
let p3 = createPromise('c');
let p4 = createPromise('d');
//(2)调用promise实例的then方法
//第一个参数: 成功的回调
//第二个参数: 失败的回调
p1.then(data=>{
console.log(data);
return p2;//在第一个promise的then方法中返回第二个promise对象
})
.then(data=>{//p2的then
console.log(data);
return p3;
})
.then(data=>{//p3的then
console.log(data);
return p4;
})
.then(data=>{//p4的then
console.log(data);
});
Promise中的其他方法
catch()
: 用于统一处理错误信息。catch
上面所有的promise任何一个出错就会进入catch
all()
: 将多个promise
对象放入数组中合并成一个promise
,要等所有的promise
全部执行完毕才会执行then()
: 逻辑与
race()
:将多个promise
对象放入数组中合并成一个promise
,任何一个promise
执行完毕就会执行且其他的promise
停止执行then()
: 逻辑或
Promise.prototype.catch()
还是以上面例子的代码为例
p1.then(data=>{
console.log(data);
return p2;//在第一个promise的then方法中返回第二个promise对象
})
.then(data=>{//p2的then
console.log(data);
return p3;
})
.then(data=>{//p3的then
console.log(data);
return p4;
})
.then(data=>{//p4的then
console.log(data);
})
.catch(err=>{
//统一处理出错信息:上面所有的promise,任何一个出现错误都会进入这个方法
console.log(err);
});
Promise.all()
语法:
const p = Promise.all([p1, p2, p3]);
还是以上面获取文本的代码为例,使用all
方法
//Promise.all([p1,p2,p3,p4]) : 多个promise合成一个
let pAll = Promise.all([p1,p2,p3,p4]);
//(2)调用promise实例的then方法
pAll.then(data=>{
//执行时机: pAll中 所有 promise完成才执行then
//data是一个数组,依次存储每一个promise的结果
console.log(data);
});
Promise.race()
语法:
const p = Promise.race([p1, p2, p3]);
// race():将多个promise对象合并为一个promise,只要有任何一个promise完成就会执行then,且其他promise停止执行
let pAll = Promise.race([p1,p2,p3,p4]);
//(2)调用promise实例的then方法
pAll.then(data=>{
//执行时机: pAll中 任何一个 promise完成就会执行then
//data : 第一个执行完毕的promise的结果
console.log(data);
});
async函数
async函数是使用
async
关键字声明的函数。 async函数是AsyncFunction
构造函数的实例, 并且其中允许使用await
关键字。async
和await
关键字让我们可以用一种更简洁的方式写出基于Promise
的异步行为,而无需刻意地链式调用promise
。
async函数还可以被作为表达式来定义。
————来自mdn中async函数
async的好处是在不阻塞主线程的情况下使用同步代码异步访问资源的能力,
也就是同步代码,异步执行。
作用:
将异步的代码以同步的方式进行书写
用法:
-
async
用来修饰异步代码所在的函数 -
await
用来修饰异步代码 - 使用
await
修饰后的异步代码可以同步的方式来接收返回结果
async function name([param[, param[, ... param]]]) {
statements
}
参数
name
函数名称。
param
要传递给函数的参数的名称。
statements
包含函数主体的表达式。可以使用await机制。
返回值
一个Promise
,这个promise要么会通过一个由async函数返回的值被解决,要么会通过一个从async函数中抛出的(或其中没有被捕获到的)异常被拒绝。
注意点:
await 修饰的异步函数必须返回一个 promise 对象
async & await 修改的代码依旧是异步代码,只是写法变成为了同步
try...catch
作用:捕获代码的异常
try {
可能报错的代码
}catch(error){
(error)不想要错误信息时,(error)带括号一起删除
error就是报的错误
如果try里面代码报错了,这里的catch就会执行
如果try里面代码没报错了,这里的catch就不会执行
}
例子:
async function getData() {
try {
const res = await axios({
url: "http://localhost:1337/au/code123",
method: "post",
data: {
mobile: "13695956584",
},
});
// .then((res) => {
window.console.log(res);
// })
} catch (error) {
// .catch((error) => {
window.console.log(error);
alert("出错了");
// });
}
window.console.log(123);
}