1. 为什么要用Promise?
- 支持链式调用,可以解决回调地域问题(回调地狱:不便于阅读和异常处理)
- 指定回调函数的方式更加灵活
2. Promise初体验
// resolve 接收 函数类型的数据
// reject 拒绝 函数类型的数据
const p = new Promise((resolve, reject)=>{
setTimeout(()=>{
let n = (0, 100)之间的随机数
if(n <= 30){
// 将Promise对象的状态设置为 【成功】
resolve(n)
} else {
// 将Promise对象的状态设置为 【失败】
reject(n)
}
}, 1000)
});
// 调用then方法
p.then((value)=>{
alert('恭喜中奖啦' + value)
}, (reason)=>{
alert('再接再厉吧' + reason)
})
3. Promise实践练习——fs读取文件
const fs = require('fs')
// 回调函数 形式
fs.readFile('要读取的文件路径', (err, data) => {
// 如果出错,抛出异常
if(err) throw err;
// 如果成功,打印读取到的文件内容
console.log(data)
});
// Promise 形式
let p = new Promise((resolve, reject) => {
fs.readFile('要读取的文件路径', (err, data) => {
// 如果出错
if(err) reject(err)
// 如果成功
resolve(data)
})
});
// 调用then
p.then(value=> {
// 转换成字符串类型,否则是Buffer类型
console.log(value.toString())
}, reason => {
console.log(reason)
})
4. Promise实践练习——ajax请求
// 接口地址: https://api.apiopen.top/getToke
// 随便一个元素绑定点击事件
$('.btn').on('click', function(){
const p = new Promise((resolve, reject) => {
// 1.创建对象
const xhr = new XMLHttpRequest();
// 2.初始化
xhr.open('GET', '接口地址');
// 3.发送
xhr.send();
// 4.处理响应结果
xhr.onreadystatechange = function(){
if(xhr.readyState === 4){
// 判断响应状态码
if(xhr.status >= 200 && xhr.status < 300){
// 成功,控制台输出响应体
resolve(xhr.response);
}else {
// 失败,控制台输出状态码
reject(xhr.status);
}
}
}
});
// 调用then
p.then(value => {
console.log(value);
}, reason => {
console.log(reason);
});
})
5. Promise封装fs读取文件操作
// 封装一个函数 mineReadFile 读取文件内容
// 参数:path 文件路径
// 返回:promise 对象
// 需要在nodejs环境下运行
function mineReadFile(path){
return new Promise((resolve, reject) => {
require('fs').readFile(path, (err, data) => {
// 读取错误
if(err) reject(err);
// 读取成功
resolve(data);
})
});
}
mineReadFile('要读取的文件路径')
.then(value => {
console.log(value.toString());
}, reason => {
console.log(reason);
})
6. util.promisify方法进行promise风格转化
// util.promise 方法
// 引入 util 模块
const util = require('util')
// 引入 fs 模块
const fs = require('fs')
// 返回一个新的函数
let mineReadFile = util.promisify(fs.readFile);
mineReadFile('要读取的文件路径')
.then(value => {
console.log(value.toString)
}, reason => {
console.log(reason)
})
7. Promise封装ajax请求
// 封装一个函数 sendAJAX 发送 GET AJAX 请求
// 参数 URL
// 返回结果 Promise 对象
function sendAJAX(url){
return new Promise((resolve, reject) => {
const xhr = new XMLHttpResquest();
xhr.responseType = 'json';
xhr.open('GET', url);
xhr.send();
// 处理结果
xhr.onreadystatechange = function(){
if(xhr.readyState === 4){
if(xhr.status >= 200 && xhr.status < 300){
resolve(xhr.response);
}else {
reject(xhr.status);
}
}
}
})
}
sendAJAX('要调用的接口地址')
.then(value => {
console.log(value);
}, reason => {
console.warn(reason);
})
8. Promise对象状态属性介绍(PromiseState)
- pending变为resolved / fulfilled
- pending变为rejected
- 说明:只有这两种,且一个promise对象只能改变一次,无论变为成功还是失败,都会有一个结果数据,成功的结果数据一般称为value,失败的结果数据一般称为reason
9. Promise对象结果值属性介绍(PromiseResult)
- 保存着异步任务【成功/失败】的结果
- resolve / reject可以设置PromiseResult的值
10. Promise工作流程
11. Promise的API—构造函数—then—catch
- Promise(excutor){}
- Promise.prototype.then
- Promoise.prototype.catch
- Promise.resolve
// 如果传入的参数为 非Promise 类型的对象,则返回的结果为成功promise对象 // 如果传入的参数为 Promise 对象,则参数的结果决定了 resolve 的结果 let p1 = Promise.resolve(521); let p2 = Promise((resolve, reject) => { reject('error') }) console.log(p1); console.log(p2); p2.catch(reason => { console.log(reason) })
-
Promise.reject
// 传入什么,失败的结果就是什么 let p = Promise.reject(521); let p2 = Promise.reject('hello world'); let p3 = Promise.reiect(Promise(resolve, reject) => { resolve('ok') }) console.log(p3)
-
Promise.all:(promise) => {} promise包含n个promise的数组
说明:返回一个新的promise,只有所有的promise都成功才成功,只要有一个失败了就直接失败;成功返回每一个成功promise的成功的结果组成的数组,失败返回失败的那个promise对象失败的结果。
let p1 = new Promise((resolve, reject) => { resolve('OK') }); let p2 = new Promise.resolve('Yes'); // let p2 = new Promise.reject('NO'); let p3 = new Promise.resolve('Success'); const result = Promise.all([p1, p2, p3]); console.log(result);
-
Promise.race:(promise) => {} promise包含n个promise的数组 说明:返回一个新的promise,第一个完成的promise的结果状态就是最终的结果状态
let p1 = new Promise((resolve, reject) => { setTimeout(() => { resolve('OK') }, 1000) }); let p2 = new Promise.resolve('Yes'); // let p2 = new Promise.reject('NO'); let p3 = new Promise.resolve('Success'); const result = Promise.race([p1, p2, p3]); console.log(result);
12. Promise关键问题
- Promise对象状态改变的方式
let p = new Promise((resolve, reject) => { // 1.resolve 函数 // resolve('ok'); // pending => fullfilled / resolved // 2.reject 函数 // reject('error'); // pending => rejected // 3.抛出错误 // throw '出问题了'; }); console.log(p);
- Promise指定多个成功/失败回调函数,都会调用吗?(当promise改变为对应状态时都会调用)
let p = new Promise((resolve, reject) => { // 有改变对应状态的话就下面两个都会调用,没有改变状态就不会调用 resolve('ok') }); p.then(value => { console.log('ok'); }); p.then(value => { alert('ok') })
- 改变promise状态和指定回调函数谁先谁后?
let p = new Promise((resolve, reject) => { // setTimeout(() => { resolve('ok') // }) }); p.then(value => { console.log(value) })
(1)都有可能,正常情况下是先指定回调再改变状态,但也可以先改变状态再指定回调
(2)如何先改变状态再指定回调?
① 在执行器直接调用 resolve() / reject()
② 延迟更长时间才调用 then()
(3) 什么时候才能得到数据?
① 如果先指定的回调,那当状态发生改变时,回调函数就会调用,得到数据
② 如果先改变的状态,那当指定回调时,回调函数就会调用,得到数据
- promise.then()返回的新promise的结果状态由什么决定?
let p = new Promise((resolve, reject) => { resolve('ok') }); let result = p.then(value => { // console.log(value) // 1.抛出错误 // throw ('出了问题'); // 2.返回结果是非Promise类型的对象 // return 521; // 3.返回结果是Promise对象 return new Promise((resolve, reject) => { // resolve('success'); reject('error'); }); }, reason => { console.warn(reason) });
(1)简单表述:由then()指定的回调函数执行的结果决定
(2)详细表达:
① 如果抛出异常,新promise变为rejected, reason为抛出的异常
② 如果返回的是非promise的任意值,新promise变为resolved,value为返回的值
③ 如果返回的是另一个新promise,此promise的结果就会成为新promise的结果
- promise如何串连多个操作任务?
let p = new Promise((resolve, reject) => { setTimeout(()=>{ resolve('ok'); }, 1000) }); p.then(value => { return new Promise((resolve, reject) => { resolve('success') }); }).then(value => { console.log(value) // success }).then(value => { console.log(value) // undefined })
(1)promise的then()返回一个新的promise,可以看成then()的链式调用
(2)通过then的链式调用串连多个同步/异步任务
-
中断promise链?
let p = new Promise((resolve, reject) => { setTimeout(()=>{ resolve('ok'); // reject('err') }, 1000) }); p.then(value => { // console.log(111); // 链式穿透 // throw 'ERROR' // 中断 有且只有一个方式 return new Promise(() => {}); }).then(value => { console.log(222); }).then(value => { console.log(333); }).catch(reason => { console.log(reason); });
(1)当使用promise的then链式调用时,在中间中断,不再调用后面的回调函数
(2)办法:在回调函数中返回一个pending状态的promise对象
我真的真的真的不会弄这个有序列表,离谱!呸!
13. Promise自定义封装
// 实例化对象
let p = new Promise((resolve, reject) => {
// 同步任务下then返回结果
// resolve('ok')
// 异步任务下then的返回结果
setTimeout(() => {
resolve('ok');
}, 1000)
// reject('error')
// 抛出异常
// throw 'error';
// 异步任务——then方法实现
// setTimeout(() => {
// resolve('ok');
// }, 1000)
})
// console.log(p);
// p.then(value => {
// console.log(value);
// }, reason => {
// console.warn(reason);
// })
// 同步任务then返回结果
// const res = p.then(value => {
// console.log(value);
// return 'hello Promise';
// return new Promise((resolve, reject) => {
// resolve('success');
// reject('oh no');
// })
// 抛出异常
// throw "FAIL";
// }, reason => {
// console.warn(reason);
// })
// console.log(res)
// 异步任务下then的返回结果
const res = p.then(value => {
console.log(value);
}, reason => {
console.warn(reason);
})
console.log(res);
// 指定多个回调的实现
// p.then(value => {
// console.log('ok');
// }, reason => {
// console.warn('no');
// })
// p.then(value => {
// alert('ok');
// }, reason => {
// alert('no')
// })
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('OK');
}, 1000)
})
let p2 = Promise.resolve('Success');
let p3 = Promise.resolve('Oh Yeah');
// 调用all方法
// let result = Promise.all([p1, p2, p3]);
// 调用race方法
// let result = Promise.race([p1, p2, p3]);
console.log(result);
// 回调函数异步执行
let p1 = new Promise((resolve, reject) => {
resolve('OK');
});
p1.then(value => {
console.log(value);
})
// class版本封装
class Promise{
// 构造方法
constructor(executor){
// 添加属性
this.PromiseState = 'pending';
this.PromiseResult = null;
// 指定多个回调时,使每个回调函数都能被执行
this.callbacks = [];
// 保存实例对象的this值 self _this that
const self = this;
// resolve函数
function resolve(data){
// 判断状态,使Promise对象状态只能修改一次
if(self.PromiseState !== 'pending') return;
// 1.修改对象的状态(promiseState)
self.PromiseState = 'fulfilled';
// 2.修改对象结果值(promiseResult)
self.PromiseResult = data;
// 异步时,判断调用then方法时,有没有保存对应的回调函数。调用成功的回调函数
// 遍历回调函数数组,执行所有被保存的失败的回调函数
setTimeout(() => {
self.callbacks.forEach(item => {
item.onResolved(data);
})
});
}
// reject函数
function reject(data){
// 判断状态,使Promise对象状态只能修改一次
if(self.PromiseState !== 'pending') return;
// 1.修改对象的状态(promiseState)
self.PromiseState = 'rejected';
// 2.修改对象结果值(promiseResult)
self.PromiseResult = data;
// 异步时,判断调用then方法时,有没有保存对应的回调函数。调用失败的回调函数
// 遍历回调函数数组,执行所有被保存的成功的回调函数
setTimeout(() => {
self.callbacks.forEach(item => {
item.onRejected(data);
})
});
}
try{
// 同步调用【执行器函数】
executor(resolve, reject);
}catch(e){
// 抛出异常时,修改promise对象状态为【失败】
reject(e);
}
}
// then方法封装
then(onResolved, onRejected){
const self = this;
// 判断回调函数参数
if(typeof onRejected !== 'function'){
onRejected = reason => {
throw reason;
}
}
if(typeof onResolved !== 'function'){
onResolved = value => value;
}
return new Promise((resolve, reject) => {
// 封装函数
function callback(type){
try {
// 获取回调函数的执行结果
let result = type(self.PromiseResult)
// 判断
if(result instanceof Promise){
// 如果是Promise类型的对象
result.then(v => {
resolve(v);
}, r => {
reject(r);
})
}else {
// 结果的对象状态为【成功/失败】
resolve(result);
}
}catch(e) {
reject(e);
}
}
// 同步时,在调用then方法时,Promise状态已经改变了,可以直接调用回调函数
// 调用回调函数
if(this.PromiseState === 'fulfilled'){
setTimeout(() => {
callback(onResolved);
});
}
if(this.PromiseState === 'rejected'){
setTimeout(() => {
callback(onRejected);
});
}
// 异步时,调用then方法时,Promise的状态还没有改变,将then方法调用的回调函数保存起来,等异步方法执行结束后,也就是Promise的状态改变后,让resolve()方法和reject()方法调用该回调函数
if(this.PromiseState === 'pending'){
// 保存回调函数
// 防止then方法指定了多个回调时,只保存最后一个回调函数。所以通过push的方法,将指定的多个回调函数全部保存到callbacks数组中
this.callbacks.push({
onResolved: function(){
callback(onResolved);
},
onRejected: function(){
callback(onRejected);
}
});
}
})
}
// catch方法封装
catch(onRejected){
return this.then(undefined, onRejected);
}
// resolve方法封装
static resolve(value){
// 返回promise对象
return new Promise((resolve, reject) => {
if(value instanceof Promise){
value.then(v => {
resolve(v);
}, r => {
reject(r);
})
} else {
// 状态设置为成功
resolve(value);
}
})
}
// reject方法封装
static reject(reason){
return new Promise((resolve, reject) => {
reject(reason);
})
}
// all方法封装
static all(promises){
// 返回结果
return new Promise((resolve, reject) => {
// 声明变量
let count = 0;
// 存放成功结果的数组
let arr = [];
// 遍历
for(let i=0;i<promises.length;i++){
//
promises[i].then(v => {
// 得知对象的状态是成功
// 每个promise对象都成功
count++;
// 将当前promise对象成功的结果,存入到数组中
arr[i] = v;
// 判断
if(count === promises.length){
// 修改状态
resolve(arr);
}
}, r => {
reject(r);
})
}
})
}
// race方法封装
static race(promises){
return new Promise((resolve, reject) => {
for(let i=0;i<promise.length;i++){
promises[i].then(v => {
// 修改返回对象的状态为【成功】
resolve(v);
}, r => {
// 修改返回对象的状态为【失败】
reject(r);
})
}
})
}
}
绕来绕去的,头都要炸掉了!!!!!!!!
14. async函数
-
async function main(){ // 1.如果返回值是一个非Promise类型的数据,结果就是一个成功状态的promise对象,而且你返回的数据就是成功的结果值 return 521; // 2.如果返回值是一个Promise类型的数据,该promise返回的状态和结果就是main函数的状态和结果 return new Promise((resolve, reject) => { resolve('OK') }) // 3.抛出异常,结果就是一个失败的Promise对象,而且抛出的结果就是失败的结果值 throw 'oh no' } let result = main(); console.log(result);
15. await表达式
- await右侧的表达式一般为promise对象,但也可以是其他的值
- 如果表达式是promise对象,await返回的是promise成功的值
- 如果表达式是其他值,直接将此值作为await的返回值
16. 注意
- await必须写在async函数中,但async函数中可以没有await
- 如果await的promise失败了,就会抛出异常,需要通过try...catch捕获处理
17. async与await结合
-
18. async与await结合发生ajax请求
农历27号啦!快过年了,无心上班,干脆直接截图了,其实后面都没咋听了哈哈哈哈。明天就回家了,过年给它补回来!