1、发自灵魂的提问 : 什么是promise ? enenen…
a. Promise是JS异步编程中的重要概念和思想,在这个容器里面保存着某个未来才会结束的事件(通常返回一个事件结果);
Promise之前是通过回调函数来实现的但是嵌套逻辑太深
例:
const fs = require('fs');
fs.readFile('1.txt', (err,data) => {
fs.readFile('2.txt', (err,data) => {
fs.readFile('3.txt', (err,data) => {
//可能还有后续代码
});
});
});
Promise实现可以更友好的处理抱错信息和代码可阅读性
例:
const readFile = function(fileName){
return new Promise((resolve, reject)=>{
fs.readFile(fileName, (err, data)=>{
if(err){
reject(err)
} else {
resolve(data)
}
})
})
}
readFile('1.txt')
.then(data => {
return readFile('2.txt');
}).then(data => {
return readFile('3.txt');
}).then(data => {
//...
});
2、Promise规范
Promise最早是在commonjs社区提出来的,当时提出了很多规范。比较接受的是promise/A规范。但是promise/A规范比较简单,后来人们在这个基础上,提出了promise/A+规范,也就是实际上的业内推行的规范;es6也是采用的这种规范,但是es6在此规范上还加入了Promise.all、Promise.race、Promise.catch、Promise.resolve、Promise.reject等方法。
Promise的基本使用
const promise = new Promise(function(resolve, reject){
console.log('1')
setTimeout(function(){
resolve(2)
}, 1000)
});
promise.then(function(res){
console.log('suc',res)
},function(err){
console.log('err',err)
})
3、Promise规范的三种状态单向不可逆
等待态(初始状态)(Pending)、执行态(Fulfilled)和拒绝态(Rejected)
// 三种状态
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
class Promise1 {
FULFILLED_CALLBACK_LIST = []; // pending状态存储.then成功的回调
REJECTED_CALLBACK_LIST = []; // 失败的回调
constructor(fn) {
this.status = PENDING; // 初始状态
this.value = null; // 成功结果
this.reason = null; // 失败原因
try {
fn(this.resolve.bind(this), this.reject.bind(this));
} catch (error) {
this.reject(error);
}
}
}
3.1 resolve【成功】和 reject 【失败】方法设置状态值
resolve(value) {
if (this.status === PENDING) {
this.status = FULFILLED;
this.value = value;
// 把当前的指传给后面then回调
this.FULFILLED_CALLBACK_LIST.forEach((fn) => fn(value));
}
}
reject(reason) {
if (this.status === PENDING) {
this.status = REJECTED;
this.reason = reason;
this.REJECTED_CALLBACK_LIST.forEach((fn) => fn(reason));
}
}
4、then当Promise状态改变后不管成功还是失败都会触发then回调函数
promise.then(onFulfilled,onRejected)
- onFulfilled 和 onRejected 都是可选参数。如果 onFulfilled 不是函数,其必须被忽略。如果 onRejected 不是函数,其必须被忽略。
- onFulfilled/onRejected 是微任务 可用queueMicrotask 或者 setTimeout来实现微任务调用且只能调用一次。
- Promise 状态变成fufilled时 调用onFulfilled 参数是 value 在Promise变成 fulfilled前不应该被调用
- Promise 状态变成rejected时应该调用onRejected参数是reason在Promise变成rejected前不应该被调用
5、then方法可以被多次调用
- promise状态变成 fulfilled 后,所有的 onFulfilled 回调都需要按照then的顺序执行, 也就是按照注册顺序执行(所以在实现的时候需要一个数组来存放多个onFulfilled的回调)
- promise状态变成 rejected 后,所有的 onRejected 回调都需要按照then的顺序执行, 也就是按照注册顺序执行(所以在实现的时候需要一个数组来存放多个onRejected的回调)
FULFILLED_CALLBACK_LIST = []; // 成功的回调
REJECTED_CALLBACK_LIST = []; // 失败的回调
/**
*
* @param {function} onFulfilled 成功回调
* @param {function} onRejected 失败回调
* @returns value
*/
then(onFulfilled, onRejected) {
/**onFulfilled/onRejected判断是否为函数 */
const fulFilledFn = this.isFunction(onFulfilled) ? onFulfilled : (value) => value;
const rejectedFn = this.isFunction(onRejected) ? onRejected: (reason) => { throw reason; };
if (this.status === FULFILLED) {
const newPromise = new Promise1((resolve, reject) => {
return setTimeout(() => {
try {
/**如果不是函数直接返回值 */
if (!this.isFunction(onFulfilled)) {
resolve(this.value);
} else {
/**如果是函数则继续处理数据 */
const x = fulFilledFn(this.value);
this.resolvePromise(newPromise, x, resolve, reject);
}
} catch (error) {
reject(error);
}
});
});
return newPromise;
} else if (this.status === REJECTED) {
const newPromise = new Promise1((resolve, reject) => {
return setTimeout(() => {
try {
/**如果不是函数直接返回抱错原因 */
if (!this.isFunction(onRejected)) {
reject(this.reason);
} else {
/**如果是函数则继续处理数据 */
const x = rejectedFn(this.reason);
this.resolvePromise(newPromise, x, resolve, reject);
}
} catch (e) {
reject(e);
}
});
});
} else if (this.status === PENDING) {
/*** 1. 那么我们首先要拿到所有的回调, 然后才能在某个时机去执行他. 新建两个数组, 来分别存储成功和失败的回调, 调用then的时候, 如果还是pending就存入数组.*/
const newPromise = new Promise1((resolve, reject) => {
this.FULFILLED_CALLBACK_LIST.push(() => {
setTimeout(() => {
try {
if (!this.isFunction(onFulfilled)) {
resolve(this.value);
} else {
const x = fulFilledFn(this.value);
this.resolvePromise(newPromise, x, resolve, reject);
}
} catch (error) {
reject(error);
}
});
});
this.REJECTED_CALLBACK_LIST.push(() => {
setTimeout(() => {
try {
if (!this.isFunction(onRejected)) {
reject(this.reason);
} else {
const x = rejectedFn(this.reason);
this.resolvePromise(newPromise, x, resolve, reject);
}
} catch (e) {
reject(e);
}
});
});
});
return newPromise;
}
}
6、then返回值是一个Promise
const promise2 = promise.then(onFulfilled,onRejected);
- 如果 onFulfilled 或者 onRejected 返回一个值 x ,则运行下面的 Promise 解决过程 调用 resolvePromise
- 如果 onFulfilled 或者 onRejected 抛出一个异常 e ,则 promise2 必须拒绝执行,并返回拒因 e
- 如果 onFulfilled 不是函数且 promise1 成功执行, promise2 必须成功执行并返回相同的值
- 如果 onRejected 不是函数且 promise1 拒绝执行, promise2 必须拒绝执行并返回相同的据因
首先第一点,我们知道onFulfilled和onRejected执行之后都会有一个返回值x,对返回值x处理就需要用到Promise解决过程,这个我们下面再说;第二点需要对onFulfilled和onRejected进行异常处理,没什么好说的;第三和第四点,说的其实是一个问题,如果onFulfilled和onRejected两个参数没有传,则继续往下传(值的传递特性);举个例子:
const promise = new Promise(function(resolve, reject){
setTimeout(function(){
resolve(3)
}, 1000)
});
promise.then(1,1)
.then('','')
.then()
.then(function(res){
// 3
console.log(res)
})
7、Promise解决过程resolvePromise
/**
*
* @param {Promise} promise2 新Promise对象
* @param {*} x 上一个then的返回值
* @param {*} resolve promise2的resolve
* @param {*} reject promise2的reject
*/
function resolvePromise(promise2, x, resolve, reject) {}
定义好函数后,来看具体的操作说明:
- x 与 promise 相等
- 如果 promise 和 x 指向同一对象,以 TypeError 为据因拒绝执行 promise
- x 为 Promise
- 如果 x 处于等待态, promise 需保持为等待态直至 x 被执行或拒绝
- 如果 x 处于执行态,用相同的值执行 promise
- 如果 x 处于拒绝态,用相同的据因拒绝 promise
- x 为对象或函数
- 把 x.then 赋值给 then
- 如果取 x.then 的值时抛出错误 e ,则以 e 为据因拒绝 promise
- 如果 then 是函数,将 x 作为函数的作用域 this 调用之。传递两个回调函数作为参数,第一个参数叫做 resolvePromise ,第二个参数叫做 rejectPromise:
- 如果 resolvePromise 以值 y 为参数被调用,则运行Resolve
- 如果 rejectPromise 以据因 r 为参数被调用,则以据因 r 拒绝 promise
- 如果 resolvePromise 和 rejectPromise 均被调用,或者被同一参数调用了多次,则优先采用首次调用并忽略剩下的调用
- 如果 then 不是函数,以 x 为参数执行 promise
- 如果 x 不为对象或者函数,以 x 为参数执行 promise
首先第一点,如果x和promise相等,这是一种什么情况呢,就是相当于把自己返回出去了:
//Uncaught (in promise) TypeError: Chaining cycle detected for promise #<Promise>
const promise2 = p.then(function(){
return promise2
})
这样会陷入一个死循环中,因此我们首先要把这种情况给排除掉:
function resolvePromise(promise2, x, resolve, reject) {
if (promise2 === x) {
reject(new TypeError('Chaining cycle'));
}
}
例子:
/**
*
* @param {Promise} newPromise 新Promise对象
* @param {*} x 上一个then的返回值
* @param {*} resolve newPromise的resolve
* @param {*} reject newPromise的reject
*/
resolvePromise(newPromise, x, resolve, reject) {
if (newPromise === x) {
return reject(new TypeError("你的小p 不能想同哦,会死循环的!"));
}
if (x instanceof Promise1) {
// 如果是个promise则继续执行newPromise
x.then((y) => {
this.resolvePromise(newPromise, y, resolve, reject);
}, reject);
} else if ((x && typeof x === "object") || this.isFunction(x)) {
// 判断是否有then
let then = null;
try {
then = x.then;
} catch (error) {
return reject(error);
}
// 如果是函数
if (this.isFunction(then)) {
// 确保调用一次
let called = false;
try {
then.call(
x,
(y) => {
if (called) {
return;
}
called = true;
this.resolvePromise(newPromise, y, resolve, reject);
},
(r) => {
if (called) {
return;
}
called = true;
reject(r);
}
);
} catch (error) {
if (called) return;
reject(error);
}
}
} else {
resolve(x);
}
}
8、完整代码
// 三种状态
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
class Promise1 {
FULFILLED_CALLBACK_LIST = []; // 成功的回调
REJECTED_CALLBACK_LIST = []; // 失败的回调
constructor(fn) {
this.status = PENDING;
this.value = null; // 成功结果
this.reason = null; // 失败原因
try {
fn(this.resolve.bind(this), this.reject.bind(this));
} catch (error) {
this.reject(error);
}
}
resolve(value) {
if (this.status === PENDING) {
this.status = FULFILLED;
this.value = value;
this.FULFILLED_CALLBACK_LIST.forEach((fn) => fn(value));
}
}
reject(reason) {
if (this.status === PENDING) {
this.status = REJECTED;
this.reason = reason;
this.REJECTED_CALLBACK_LIST.forEach((fn) => fn(reason));
}
}
/**
* 判断是否为函数
* @param {any} param
* @returns
*/
isFunction(param) {
return typeof param === "function";
}
/**
*
* @param {function} onFulfilled 成功回调
* @param {function} onRejected 失败回调
* @returns value
*/
then(onFulfilled, onRejected) {
/**onFulfilled/onRejected判断是否为函数 */
const fulFilledFn = this.isFunction(onFulfilled) ? onFulfilled : (value) => value;
const rejectedFn = this.isFunction(onRejected) ? onRejected: (reason) => { throw reason; };
if (this.status === FULFILLED) {
const newPromise = new Promise1((resolve, reject) => {
return setTimeout(() => {
try {
/**如果不是函数直接返回值 */
if (!this.isFunction(onFulfilled)) {
resolve(this.value);
} else {
/**如果是函数则继续处理数据 */
const x = fulFilledFn(this.value);
this.resolvePromise(newPromise, x, resolve, reject);
}
} catch (error) {
reject(error);
}
});
});
return newPromise;
} else if (this.status === REJECTED) {
const newPromise = new Promise1((resolve, reject) => {
return setTimeout(() => {
try {
/**如果不是函数直接返回抱错原因 */
if (!this.isFunction(onRejected)) {
reject(this.reason);
} else {
/**如果是函数则继续处理数据 */
const x = rejectedFn(this.reason);
this.resolvePromise(newPromise, x, resolve, reject);
}
} catch (e) {
reject(e);
}
});
});
} else if (this.status === PENDING) {
/*** */
const newPromise = new Promise1((resolve, reject) => {
this.FULFILLED_CALLBACK_LIST.push(() => {
setTimeout(() => {
try {
if (!this.isFunction(onFulfilled)) {
resolve(this.value);
} else {
const x = fulFilledFn(this.value);
this.resolvePromise(newPromise, x, resolve, reject);
}
} catch (error) {
reject(error);
}
});
});
this.REJECTED_CALLBACK_LIST.push(() => {
setTimeout(() => {
try {
if (!this.isFunction(onRejected)) {
reject(this.reason);
} else {
const x = rejectedFn(this.reason);
this.resolvePromise(newPromise, x, resolve, reject);
}
} catch (e) {
reject(e);
}
});
});
});
return newPromise;
}
}
/**
*
* @param {Promise} newPromise 新Promise对象
* @param {*} x 上一个then的返回值
* @param {*} resolve newPromise的resolve
* @param {*} reject newPromise的reject
*/
resolvePromise(newPromise, x, resolve, reject) {
if (newPromise === x) {
return reject(new TypeError("你的小p 不能想同哦,会死循环的!"));
}
if (x instanceof Promise1) {
// 如果是个promise则继续执行newPromise
x.then((y) => {
this.resolvePromise(newPromise, y, resolve, reject);
}, reject);
} else if ((x && typeof x === "object") || this.isFunction(x)) {
// 判断是否有then
let then = null;
try {
then = x.then;
} catch (error) {
return reject(error);
}
// 如果是函数
if (this.isFunction(then)) {
// 确保调用一次
let called = false;
try {
then.call(
x,
(y) => {
if (called) {
return;
}
called = true;
this.resolvePromise(newPromise, y, resolve, reject);
},
(r) => {
if (called) {
return;
}
called = true;
reject(r);
}
);
} catch (error) {
if (called) return;
reject(error);
}
}
} else {
resolve(x);
}
}
}
async function haha() {
const a = await new Promise1((resolve, reject) => {
// console.log("222");
resolve("hahah");
})
.then((value) => {
console.log(value, "value");
return "---11";
})
.then((value) => {
console.log(value, "-valuevalue--");
return value + "----";
});
console.log(a, "aaa");
}
haha();