Promise深入了解
一、promise基本使用
promise
是js中进行异步编程的解决方案。
Promise 实例(用Promise封装异步操作):
resolve
:解决 函数类型的数据
reject
:拒绝 函数类型的数据
调用then
方法:第一个参数 状态为成功的回调函数;第二个参数 状态为失败的回调函数
1. 读取文件(node环境)
const fs = require('fs');
//Promise 形式
let p = new Promise((resolve, reject) => {
fs.readFile('./resource/content.txt', (err, data) => {
if (err) reject(err);
resolve(data);
});
});
p.then(
(value) => {
console.log(value.toString());
},
(reason) => {
console.log(reason);
}
);
2. 发送请求
const p = new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', 'http://127.0.0.1:8000/server');
xhr.send();
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300)
resolve(xhr.response);
else {
reject(xhr.status);
}
}
};
});
p.then(
(value) => {
console.log(value);
},
(reason) => {
console.warn(reason);
}
);
二、Promise封装
1. 读取文件(node环境)
function mineReadFile(path) {
return new Promise((resolve, reject) => {
require('fs').readFile(path, (err, data) => {
if (err) reject(err);
resolve(data);
});
});
}
mineReadFile('./resource/content.txt').then(
(value) => {
console.log(value.toString());
},
(reason) => {
console.log(reason);
}
);
2. 发送请求
以下代码与平时开发用到的请求形式非常相似。
function sendAJAX(url) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
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('http://127.0.0.1:8000/server').then(
(value) => {
console.log(value);
},
(reason) => {
console.warn(reason);
}
);
三、Promise的API
1. catch
let p = new Promise((resolve, reject) => {
reject('error');
});
// catch方法用来指定失败的回调函数
p.catch((reason) => {
console.log(reason);
});
2. resolve
// 传入参数为 非Promise类型的对象,则返回的结果为成功的promise对象
let p1 = Promise.resolve('521');
// 传入参数为 Promise 对象,则参数的结果决定了 resolve 的结果
let p2 = Promise.resolve(
new Promise((resolve, reject) => {
// resolve('ok'); //内部成功则外部也成功 且结果一样
reject('err'); //内部失败则外部也失败
})
);
3. reject
// 返回结果永远都是失败 传什么结果为什么
let p = Promise.reject('521');
let p1 = Promise.reject( // 结果为promise对象
new Promise((resolve, reject) => {
resolve('ok');
})
);
4. all
let p1 = new Promise((resolve, reject) => {
resolve('ok');
});
let p2 = new Promise((resolve, reject) => {
resolve('Success');
});
let p3 = new Promise((resolve, reject) => {
resolve('OHHHHH');
});
let p4 = new Promise((resolve, reject) => {
reject('err');
});
const result = Promise.all([p1, p2, p3]); //全部成功则成功 返回值为所有成功结果的集合
const result1 = Promise.all([p1, p2, p4]); //有一个失败就失败 返回值为失败的结果
console.log(result);
console.log(result1);
5. race
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('ok');
}, 1000);
});
let p2 = new Promise((resolve, reject) => {
resolve('Success');
});
let p3 = new Promise((resolve, reject) => {
resolve('OHHHHH');
});
// 谁先改变状态,则他的结果为返回值
const result = Promise.race([p1, p2, p3]);
console.log(result);
Promise对象有三种状态:
初始化状态:pending
resolve('ok');
pending -> fulfilled
reject('err');
pending-> rejected
四、promise创建实例简单实现
Promise构造函数参数为: executor函数 —— 执行器 ((resolve,reject)=>{})
executor 会在 Promise 内部立即同步调用,异步操作在执行器中执行。
以最初的例子为例观察:
const p = new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', 'http://127.0.0.1:8000/server');
xhr.send();
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300)
resolve(xhr.response);
else {
reject(xhr.status);
}
}
};
});
p.then(
(value) => {
console.log(value);
},
(reason) => {
console.warn(reason);
}
);
1. 首先创建类
class Promise {
constructor(executor) {
function resolve(data) {
}
function reject(error) {
}
try {
executor(resolve, reject);
} catch (error) {
//修改promise 状态为失败
reject(error);
}
}
}
2. 在then中获取resolve、reject具体执行
这里类需要添加三个属性:对象状态、对象结果值、对象回调数组。
且promise对象的then可以链式调用,所以then返回promise对象。
class Promise {
constructor(executor) {
// 添加属性
this.PromiseState = 'pending';
this.PromiseResult = null;
this.callbacks = [];
const self = this;
function resolve(data) {
if (self.PromiseState !== 'pending') return;
// 1. 修改对象的状态 (promiseState)
self.PromiseState = 'fulfilled';
// 2. 修改对象结果值 (promiseResult)
self.PromiseResult = data;
// 调用成功的回调函数,异步
setTimeout(() => {
self.callbacks.forEach((item) => {
item.onResolved(data);
});
});
}
function reject(data) {
if (self.PromiseState !== 'pending') return;
// 1. 修改对象的状态 (promiseState)
self.PromiseState = 'rejected';
// 2. 修改对象结果值 (promiseResult)
self.PromiseResult = data;
// 执行回调
setTimeout(() => {
self.callbacks.forEach((item) => {
item.onRejected(data);
});
});
}
try {
executor(resolve, reject);
} catch (error) {
//修改promise 状态为失败
reject(error);
}
}
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) {
result.then( // 支持链式调用,且结果传递
(v) => {
resolve(v);
},
(r) => {
reject(r);
}
);
} else {
resolve(result);
}
} catch (error) {
reject(error);
}
}
if (this.PromiseState === 'fulfilled') {
setTimeout(() => {
//异步
callback(onResolved);
});
}
if (this.PromiseState === 'rejected') {
setTimeout(() => {
callback(onRejected);
});
}
if (this.PromiseState === 'pending') {
// pending状态保存回调函数
this.callbacks.push({
onResolved: function() {
callback(onResolved);
},
onRejected: function() {
callback(onRejected);
},
});
}
});
}
}
分析:
若executor内的reject, resolve先于then执行,则改变对象状态,执行空回调函数数组。在p.then执行回调函数。
若executor内的reject, resolve后于then执行,则then收集回调函数,在executor内的reject, resolve执行回调函数。
五、async和await
1. async
函数返回值为Promise对象 结果由async函数执行的返回值决定
async function main() {
// 1. 返回值为非Promise类型数据 返回结果为fulfilled 结果为返回值
// 2. 返回一个Promise对象 结果和Promise的结果一致
return new Promise((resolve, reject) => {
// reject('err');
resolve('ok');
});
// 3. 抛出异常 结果失败rejected 结果为抛出的值
// throw 'Oh NO';
}
2. await
- await右侧的表达式一般为Promise对象,但也可以是其他值
- 如果表达式是Promise对象,await返回的是Promise成功的值
- 如果表达式是其他值,直接将此值作为await的返回值
- 注意:
- await必须写在async函数中,但async函数可以没有await
- 如果await的promise失败了,就会抛出异常,需要通过try…catch捕获处理
async function main() {
let p = new Promise((resolve, reject) => {
reject('err');
});
try {
let res = await p;
} catch (error) {
console.log(error);
}
}
main();
一般用async和await同步处理异步操作。
综上,完成对Promise的梳理。