JS中的Promise对象
文章目录
前言
本质是一个类:Promise(翻译:承诺;保证)
创建对象:new Promise时,传的函数叫执行器
这个执行器是立即执行的
作用:promise是为了让你更加优雅写异步代码,避免回调地狱。
回调地狱
回调地域,表示回调函数中嵌套回调函数。
利用回调函数实现异步有什么不足
:如果层数非常多,就会出现回调地域,代码的可读性不好。
创建出来的promise对象有三个状态:
1)默认情况下,处于pending状态 pendding是等待
2)成功状态,fulfilled
3)失败状态,rejected
注意:
1)处理等待状态的promise,要么转化成成功状态的promise,要么转化成失败的promise。不可能既成功又失败。
2)如果一个promise从等待转化成了成功状态,就不可以再转化成失败状态。
3)如果一个promise从等待状态转化成了失败状态,就不可能再转化成成功的状态。
1 终值(resolve)和拒因(reject)
在执行器中,有两个参数,一个resolve,一个叫reject:
- resolve(
翻译:解决;决心
):调用 resolve 以让promise对象从等待状态变成成功状态
,调用resolve,可以传递一个终值(value)。 - reject(
翻译:拒绝
):调用 reject 可以让promise从等待状态变成失败状态
,调用reject,可以传递一个拒因(reason)。
new Promise时,传的函数叫执行器 这个执行器是立即执行的。
let p1 = new Promise(function(resolve,reject){//两个参数
// "包包"叫终值 成功的结果
// resolve("包包")
// 一旦成功了,就不能再转成失败态
// "没钱"叫拒因 失败的结果
reject("没钱");
});
// console.log(p1); // Promise { <pending> } pending是等待的意思
// console.log(p1); // Promise { '包包' }
console.log(p1); // Promise { <rejected> '没钱' }
2 then
在promise
对象上有一个方法,叫then,then这个方法中,可以传递两个函数。
只有promise
对象才能.then
。
then方法的第一个参数是resolved状态的回调函数,第二个参数(可选)是rejected状态的回调函数。
- 如果
promise
对象从等待到成功状态,就会调用then中的第1个方法,方法的第1个参数就表示终值。 - 如果
promise
对象从等等到失败状态,就会调用then中的第2个方法,方法的第1个参数就表示拒因。
then方法是定义在原型对象Promise.prototype
上的。
代码如下:
let p1 = new Promise(function(resolve,reject){
// 一旦成功了,就不能再转成失败态
// resolve("包包")
// reject("没钱");
console.log("我是否是立即执行");
});
p1.then(function(value){
console.log(value); // value叫终值 成功的结果
},function(reason){
console.log(reason); // reason叫拒因 失败的结果
});
利用Promise解决异步问题:   当我们
new Promise时,可以就在执行器中写异步代码。   简单使用promise
解决异步问题。
const fs = require("fs");
// 一般是使用Promise去包含异步代码
let p1 = new Promise(function(resolve,reject){
// 在执行器中写异步代码
fs.readFile("./nn.txt","utf-8",function(err,data){
if(err){
reject(err)
}else{
resolve(data);//这里就可以拿到nn.txt中的数据
}
})
})
p1.then(function(value){ console.log(value); },function(reason){ console.log(reason); })
封装读取文件的promise
方法。
// 封装一个函数,此函数返回promise对象
const fs = require("fs");
function readFile(filename){
return new Promise(function(resolve,reject){
// 异步代码写在执行器中
fs.readFile(filename,"utf-8",function(err,data){
if(err){
reject(err)
}else{
resolve(data)
}
})
})
}
readFile("./nn.txt").then(value=>console.log(value),reason=>console.log(reason))
在很多模块,都是别人封装的方法,直接返回promise对象
所以,碰见莫名其妙.then
的对象,就要看看它本身是不是封装好的。
const fs = require("fs").promises; // 引入fs模块的promise版本
fs.readFile("./nn.txt","utf-8").then(data=>console.log(data))
3 then链
then是一个函数调用 只要是函数调用,就有返回值。then的返回值也是一个promise。
它返回的promise
是处于什么状态,是由p1.then
中的两个函数决定的
下一个.then
中是走成功的回调函数,还是走失败的回调函数,取决于你上一个.then
中的两个函数中做了啥。
p1.then
中不管是哪个方法执行,只要不报错,新的promise
就会转成成功态(从等待状态转成成功态)。
终值:看此方法返回的结果 没有返回结果 返回und und就会作为终值
let p1 = new Promise((resolve,reject)=>{
resolve("包包")
})
p1.then(value=>{ //resolve
console.log(value); // 包包
},reason=>{ //reject
console.log(reason);
}).then(value=>{
console.log(value); // undefined
},reason=>{
console.log(reason);
})
Promise
是一个类 函数 函数也是对象
Promise.resolve(); 表示直接创建出一个成功的promise。
Promise.reject(); 表示直接创建出一个失败的promise。
let p1 = Promise.resolve("包包");
// .then时,可以不写第2个函数
p1.then(value=>{console.log(value);})
测试例题:
new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve(10)
},2000)
}).then(value => {
console.log(value) // 10
return value * n; // 报错了,会走下一个then的第2个函数
},reason => {
console.log(reason)
return Promise.reject(666);
}).then(value => {
console.log(value)
},reason => {
console.log(reason); // n is not def
return reason * 10; //return NaN 没有报错
}).then(value => {
console.log(value) // NaN
return Promise.reject(value * 100)// 返回一个失败状态的promise 返回的结果在下面
},reason => {
console.log(reason)
}).then(value=>{
},reason => {
console.log(reason) // NaN
})
// 10 n is not def NaN NaN
4 then的顺延和async和await的使用
第1个.then
中没有失败的回调 它会继续在下一个then中找失败的回调函数 如果还找不到 继续向下找。
这种情况叫做then顺延。
let p1 = new Promise((resolve,reject)=>{
reject("没钱")
})
p1.then(value=>{ ==========这个then相当于只有value终值
console.log(value);
}).then(value=>{
console.log(value);
},reason=>{
console.log(reason);=========一直找到出现拒因的then为止,这叫顺延
}).then(null,reason=>{ ==========这个then相当于只有reson拒因
console.log(reason);
4.1 .catch
语法糖
一般情况下,在then中只写一个成功的回调。
.catch
是.then
的语法糖,里面放失败的回调。
p1.then(value=>{
console.log(value);
}).catch(reason=>{
console.log("xx:"+reason);
})
4.2 async和await的使用(只能返回成功的结果)
async 可以修改一个函数;如果使用async修饰了一个函数,这个函数就会返回一个promise。
async+await
就是promise
的语法糖 用的非常多。
一般情况下,在async修饰的函数内部,会出现一个await。
- 要用
await
,必须要使用async
(否则报错)。 async
可以不使用await
(async
可以单独存在)。await
后面通常是跟一个promise
。await
后面的代码,相当于放到了一个then
中,then
中的第1个函数中。await
返回值是成功的结果,失败的结果需要通过try catch
来获取。
let p1 = new Promise((resolve,reject)=>{
setTimeout(()=>{
reject("没钱")
},2000)
})
==========================================================================================
async function fn() {
// await返回值是成功的结果
let value = await p1; // await后面跟promise 要使用await 对应的函数必须是async函数
console.log(value);
}
fn();
4.3 try catch finally(能够返回失败的结果)
语法:
try {
tryCode - 尝试执行代码块
}
catch(err) {
catchCode - 捕获错误的代码块
}
finally {
finallyCode - 无论 try / catch 结果如何都会执行的代码块
}
- 不管有没有异常,
finally
中的代码都会执行- 当
try
、catch
中有return
时,finally
中的代码依然会继续执行finally
是在return
后面的表达式运算之后执行的,此时并没有返回运算之后的值,而是把值保存起来,不管finally
对该值做任何的改变,返回的值都不会改变
,依然返回保存起来的值。也就是说方法的返回值是在finally
运算之前就确定了的。finally
代码中最好不要包含return
,程序会提前退出,也就是说返回的值不是try或catch中的值。(引用地址:传送门)
async function fn(){
console.log("start");
// await 前面只能获取成功的结果,不能获取失败的结果
// 要获取失败的结果,可以使用try catch
// try中放可能会失败的代码
try{
let value = await p1; // value就是终值,成功的结果 await本意是等待 等待p1变成功
}catch(reason){ // 失败的结果,需要在catch中捕获 catch是捕获的意思
console.log(reason);
}finally{
console.log("不管是成功还是失败,finally中的代码都会走")
}
console.log(value);
}
fn()