创建promise对象(pending状态)
const p = new Promise(executor);
其中:
executor函数
: 执行器 (resolve, reject) => {}
resolve函数
: 内部定义成功时我们调用的函数 value => {}
reject函数
: 内部定义失败时我们调用的函数 reason => {}
executor会在Promise内部立即同步调用,异步操作在执行器中执行
实例对象调用Promise原型中的then方法来完成对结果的处理
<script>
const p = new Promise((resolve, reject) => {
//如果咱们公司今年挣钱了,年底就发奖金,否则不发
resolve('ok');
})
console.log(p)
p.then(() => {
console.log('发奖金')
}, () => {
console.log('不发奖金')
})
</script>
回调函数嵌套调用,外部回调函数异步执行的结果是嵌套的回调执行的条件
不便于阅读;不便于异常处理
promise链式调用
async/await
此属性为promise对象的状态属性。
【注】状态只能由pending->fulfilled 或者是 pending->rejected
此属性为promise对象的结果值(resolve以及reject函数的形参值)
resolve
:修改promise对象的状态,由pending修改到fulfilled;将实参设置到这个属性PromiseResult中。reject
:修改promise对象的状态,由pending修改到rejected;将实参设置到这个属性PromiseResult中。案例1:利用promise来进行读取文件操作
//1.普通文件读取方式
const fs = require('fs');
//2.直接利用readfile来进行读取
/* fs.readFile(__dirname + '/data.txt',(err,data)=>{
if(err) throw err;
console.log(data.toString());
}) */
//3.利用promise来实现文件的读取
const p = new Promise((resolve, reject) => {
fs.readFile(__dirname + '/data.txt', (err, data) => {
if (err) {
reject(err);
}else{
resolve(data);
}
})
});
p.then(value=>{
console.log(value.toString());
},reason=>{
console.log(reason);
})
案例2:利用promise进行ajax请求
<body>
<button>发送ajax请求</button>
<script>
//1.获取DOM元素对象
let btn = document.querySelector('button');
//2.绑定事件
btn.onclick = function(){
//3.创建promise实例对象
const p = new Promise((resolve,reject)=>{
//4.创建ajax实例对象
const xhr = new XMLHttpRequest();
//5.打开请求
xhr.open('get','https://www.yiketianqi.com/free/day?appid=82294778&appsecret=4PKVFula&unescape=1');
//6.发送请求
xhr.send();
//7.利用onreadystatechange事件
xhr.onreadystatechange = function(){
//8.判断
if(xhr.readyState == 4){
if(xhr.status == 200){
resolve(xhr.responseText);
}else{
reject(xhr.response);
}
}
}
});
p.then(value=>{
console.log(JSON.parse(value));
},reason=>{
console.log('获取信息失败');
})
}
</script>
</body>
案例3:利用promise进行数据库操作
const mongoose = require('mongoose');
new Promise((resolve, reject) => {
mongoose.connect('mongodb://127.0.0.1/project');
mongoose.connection.on('open', ()=>{
//连接成功的情况
resolve();
});
mongoose.connection.on('error', () => {
//连接失败的情况
reject();
})
}).then(value => {
//创建结构
const NoteSchema = new mongoose.Schema({
title: String,
content: String
})
//创建模型
const NoteModel = mongoose.model('notes', NoteSchema);
//读取操作
NoteModel.find().then(value => {
console.log(value);
}, reason => {
console.log(reason);
})
}, reason => {
console.log('连接失败');
})
案例4:封装一个函数,作用是读取文件
const fs = require('fs');
function ReadFileFun(path){
return new Promise((resolve,reject)=>{
fs.readFile(path,(err,data)=>{
//判断
if(err){
reject(err)
}else{
resolve(data);
}
})
});
}
ReadFileFun('./data.txt').then(value=>{
console.log(value.toString());
},reason=>{
console.log(reason);
})
node中的promisify
只能在 NodeJS 环境中使用
)const util = require('util');
const fs = require('fs');//通过 fs.readFile 创建一个新的函数
const mineReadFile = util.promisify(fs.readFile);mineReadFile('./resource/2.html')
.then(value => {
console.log(value.toString());
}, reason => {
console.log(reason);
})
Promise对象通过自身的状态来控制异步操作,Promise实例具有三种状态.
这三种的状态的变化途径只有两种
一旦状态发生变化,就凝固了,不会再有新的状态变化,这也是Promise这个名字的由来,它的英语意思"承诺",
一旦承诺生效,就不得再改变了,这也意味着Promise实例的状态变化只可能发生一次。
在Promise对象的构造函数中,将一个函数作为第一个参数。而这个函数,就是用来处理Promise的状态变化。
上面的resolve和reject都为一个函数,他们的作用分别是将状态修改为resolved和rejected。
因此,Promise的最终结果只有两种。
异步操作成功,Promise实例传回一个值(value),状态变为fulfilled.
异步操作失败,Promise实例抛出一个错误(error),状态变为rejected
then:指定用于得到成功value的成功回调和用于得到失败reason的失败回调,返回一个新的promise对象
promise.then()返回的新promise的结果状态由什么决定?
(1) 简单表达: 由then()指定的回调函数执行的结果决定
(2) 详细表达:
① 如果抛出异常, 新promise变为rejected, reason为抛出的异常
const p = new Promise((resolve,reject)=>{
resolve('ok');
});
let result = p.then(value=>{
throw '错误';
},reason=>{
console.log(reason);
});
console.log(result);
② 如果返回的是非promise的任意值, 新promise变为fulfilled, PromiseResult为返回的值
const p = new Promise((resolve,reject)=>{
resolve('ok');
});
let result = p.then(value=>{
return 100;
},reason=>{
console.log(reason);
});
console.log(result);
③ 如果返回的是另一个新promise, 此promise的结果就会成为新promise的结果
const p = new Promise((resolve,reject)=>{
resolve('ok');
});
let result = p.then(value=>{
return new Promise((resolve,reject)=>{
//resolve('111');
reject('error');
})
},reason=>{
console.log(reason);
});
console.log(result);
const p = new Promise((resolve,reject)=>{
//resolve('ok');
reject('error');
});
p.then(value=>{
console.log(value);
},reason=>{
console.log(reason);
}).then(value=>{
console.log(value);
},reason=>{
console.log(reason);
})
案例:通过promise的链式调用来读取文件
回调地狱的方式:
const fs = require('fs');
fs.readFile('./resource/1.html',(err,data1)=>{
if(err) throw err;
fs.readFile('./resource/1.html',(err,data2)=>{
if(err) throw err;
fs.readFile('./resource/1.html',(err,data3)=>{
if(err) throw err;
console.log(data1 + data2 + data3);
})
})
})
Promise的形式:
需求:读取resource下三个文件内容,并在控制台合并输出
new Promise((resolve,reject)=>{
fs.readFile('./resource/1.html',(err,data)=>{
//如果失败 则修改promise对象状态为失败
if(err) reject(err);
//如果成功 则修改promise对象状态为成功
resolve(data);
})
}).then(value=>{
return new Promise((resolve,reject)=>{
fs.readFile('./resource/2.html',(err,data)=>{
//失败
if(err) reject(err);
//成功
resolve([value,data]);
})
})
}).then(value=>{
return new Promise((resolve,reject)=>{
fs.readFile('./resource/3.html',(err,data)=>{
//失败
if(err) reject(err);
value.push(data);
//成功
resolve(value);
})
})
}).then(value=>{
console.log(value.join(""));
})
将一个普通值转化为promise类型的数据
let p1 = Promise.resolve(123);
console.log(p1);
let p2 = Promise.resolve(undefined);
console.log(p2);
let p3 = Promise.resolve(new Promise((resolve,reject)=>{
resolve('success');
}));
console.log(p3);
let p4 = Promise.resolve(Promise.resolve(Promise.resolve("OK")));
console.log(p4);
返回的结果始终为失败的Promise对象
console.log(Promise.reject(123));
console.log(Promise.reject(Promise.resolve('ok')));
功能是用来指定失败的回调函数
let p = new Promise((resolve,reject)=>{
//resolve('success');
reject('error');
});
p.catch(reason=>{
console.log(reason);
});
//then方法中不是必须传入两个参数,可以只传递成功时的回调函数
//也可以单独使用catch来指定失败的回调函数
//异常(错误)穿透
//当如果有多个需要执行的成功时的回调函数,可以不需要每一次都写失败回调,可以统一最后利用catch
//当如果promise对象的状态为reject的话,会一直向下穿透直到catch方法
p.then(value=>{
console.log(value);
}).then(value=>{
console.log(value);
}).catch(reason=>{
console.log(reason);
})
作用:针对于多个Promise的异步任务进行处理
接收的参数:promise数组
返回值:promise对象,状态由promise数组中的对象状态
决定
都为
成功,则返回的promise对象状态为成功, 成功的结果值为每个promise对象成功结构值组成的数组
其中一个对象
状态为失败,则返回的promise对象状态为失败, 失败的结果值为失败的promise对象的结果值
let p1 = new Promise((resolve, reject) => {
resolve('ok');
})
let p2 = Promise.resolve('hello');
let p3 = Promise.resolve('oh yeah');
let result = Promise.all([p1, p2, p3])
console.log(result);
当有一个ajax请求,它的参数需要另外2个甚至更多请求都有返回结果之后才能确定,
那么这个时候,就需要用到Promise.all来帮助我们应对这个场景。
Promise.all接收一个Promise对象组成的数组作为参数,
当这个数组所有的Promise对象状态都变成resolved或者rejected的时候,它才会去调用then方法。
//ES6中对Promise.all()的理解以及应用场景
//用于将多个Promise实例,包装成一个新的Promise实例
let p1 = new Promise((resolve,reject)=>{
resolve('成功01');
})
let p2 = new Promise((resolve,reject)=>{
resolve('成功02');
}).catch(reason=>console.log(reason));
let p3 = new Promise((resolve,reject)=>{
resolve('成功03');
})
//参数可以不是数组,但必须是iterator接口
let pAll = Promise.all([p1,p2,p3]);
console.log(pAll)
//pAll的状态是由p1,p2,p3来决定,只有当这三个都为成功,pAll才会为成功,反之,但凡其中一个失败结果就是失败
//这个时候第一个失败的实力的返回值会传递给pAll的回调函数,如果作为参数的实例,自己定义了catch方法,那么它一旦为rejected,是不会触碰到pAll中的catch方法
pAll.then(value=>{
console.log(value);
},reason=>{
console.log(reason);
})
案例1:模拟请求三个接口中的数据,全部请求成功后获取。
function getUsersList() {
return new Promise((resolve, reject) => {
//模拟请求用户列表数据
setTimeout(() => {
resolve('用户列表的数据');
}, 1000);
})
}
function getBannersList() {
return new Promise((resolve, reject) => {
//模拟请求用户列表数据
setTimeout(() => {
resolve('轮播图的数据');
}, 2000);
})
}
function getVideoList() {
return new Promise((resolve, reject) => {
//模拟请求用户列表数据
setTimeout(() => {
resolve('视频列表的数据');
}, 3000);
})
}
//初始加载的时候
function initLoad() {
let all = Promise.all([getUsersList(), getBannersList(), getVideoList()]);
//获取成功请求的结果值
all.then(value => {
console.log(value);
})
}
initLoad();
案例2:修改多文件读取代码
const fs = require('fs');
const util = require('util');
const mywriteFile = util.promisify(fs.readFile);
let one = mywriteFile('./resource/1.html');
let two = mywriteFile('./resource/2.html');
let three = mywriteFile('./resource/3.html');
let result = Promise.all([one,two,three]);
result.then(value=>{
console.log(value.join(''));
},reason=>{
console.log(reason);
})
Promise.race
race 赛跑的意思
参数: promise 数组
返回结果: promise 对象
状态由『最先改变状态的 promise对象』决定
结果值由 『最先改变状态的 promise对象』决定
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('ok');
}, 2000)
});
let p2 = Promise.resolve('success');
let p3 = Promise.resolve('oh hou');
let result = Promise.race([p1, p2, p3]);
console.log(result);
与Promise.all相似的是,Promise.race都是以一个Promise对象组成的数组作为参数。
不同的是,只要当数组中的其中一个Promsie状态变成resolved或者rejected时,就可以调用.then方法了。
而传递给then方法的值也会有所不同。
<script>
//ES6中Promise.race的用法以及使用场景
//将多个Promise实例包装成一个新的Promise实例
let p1 = new Promise((resolve, rejct) => {
setTimeout(() => {
resolve('p1成功')
}, 2000);
})
let p2 = new Promise((resolve, rejct) => {
setTimeout(() => {
resolve('p2成功');
}, 1000);
}, 1000);
//调用
const prace = Promise.race([p1, p2]);
//Promise.race区别于Promise.all:
//只要是实例中有一个先改变状态,就会把这个实例的返回值传递给prace的回调函数
</script>
//使用场景:请求超时提示
function request() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('请求成功');
}, 4000);
})
}
function timeout() {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject('网络不畅,请求超时');
}, 3000);
});
}
Promise.race([request(), timeout()]).then(value => {
console.log(value)
}).catch(reason => {
console.log(reason)
})
Promise.allSettled()
方法,用来确定要一组异步操作是否都结束了(不管成功或失败)。
所以,它的名字叫"Settled",包含了"fufilled"和"rejected"两种情况.
<script>
function ajax(url) {
return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest();
xhr.open('get', url, true);
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(xhr.responseText);
} else {
reject(xhr.responseText);
}
}
}
})
}
//类比Promise下的all方法和allSettled
// Promise.all([ajax('http://www.xiongmaoyouxuan.com/api/tabs'),
// ajax('https://m.maizuo.com/gateway?cityId=110100&k=4770248')
// ]).then(value => {
// console.log(value)
// }).catch(error => {
// console.log(error);
// })
Promise.allSettled([ajax('http://www.xiongmaoyouxuan.com/api/tabs'),
ajax('https://m.maizuo.com/gateway?cityId=110100&k=4770248')
]).then(value => {
// console.log(value)
let successList = value.filter(item => item.status === 'fulfilled');
console.log(successList)
let errorList = value.filter(item => item.status === 'rejected');
console.log(errorList)
}).catch(error => {
console.log(error);
})
</script>
只要参数实例有一个变成fulfilled状态,包装实例就会变成fulfiilled状态;
如果所有参数实例都变成rejected,包装实例就会变成rejected状态。
Promise.any()跟Promise.race()方法很像,但是有一点不同,
就是Promise.any()不会因为某个Promise变成rejected状态而结束,
必须等到所有参数Promise变成rejected状态才会结束。
<script>
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('ok');
}, 1000)
})
let p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('okk');
}, 2000)
})
let p3 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('error');
}, 3000)
})
Promise.any([p1, p2, p3]).then(res => {
console.log(res)
}).catch(err => {
console.log('error')
})
</script>
finally是在ES9(ES2018)中新增的一个特性:表示无论Promise对象变成fufilled还是rejected状态,最终都会被执行。
finally方法中的回调函数
是不接受参数的,因为无论前面是fulfilled状态还是rejected状态, 它都是执行。
const p = new Promise((resolve, reject) => {
// resolve('ok');
reject('error');
});
p.then(res => {
console.log(res);
}).catch(err => {
console.log(err);
}).finally(() => {
console.log('finally')
})