总结
一、JS中的错误处理 try…catch
语法固定 try…catch try 尝试的意思 catch 捕获
1. try catch捕获到错误之后, 后续代码可以继续执行
2. catch 可以将错误信息捕获到. error参数是一个错误对象, 有message(错误信息)和stack(错误跟踪,精准到行和列)两个属性,使用console.dir(error)打印输出查看
3. 抛出错误之后, 在 try 里面的报错的后续代码就不再执行
4. try 不能捕获语法错误(syntaxError). 其他三种类型错误可以捕获(typeError类型错误、RangeError范围错误、以及throw抛出错误).
5. 允许使用 throw 手动的抛出错误
6. throw可以抛出任意类型的数据
try {
try中存入有可能会出现错误的代码(文件操作...、连接数据库....、操作数据库方法....、ajax请求...)
1、TypeError错误:
let a = 10.4656;
a = {}
// 在try中如果有哪一句话发生了错误,则后面的语句将不再执行
console.log(a.toFixed(2));
//前面的语句发生了错误,则这句123是不会在控制台中输出
// console.log(123);
2、RangeError:范围错误
//Array构造函数中的参数表示数组的预计长度,起始为0,不能为负数
// let arr = new Array(-1);
// console.log(arr);
3、SyntaxError语法错误,catch是无法捕捉的!!!
// if () {
4、throw抛出的错误,catch也是可以捕捉的,可以抛出任意类型错误
// throw new Error('错误消息');
// throw new TypeError('错误消息');
//throw后面可以抛出任意的数据类型,只要抛出了catch中的错误对象都可以捕捉
// throw 100;
// throw "我是错误字符串";
// throw true;
// throw [1, 2, 3];
} catch (e) {
//catch方法需要传入一个参数,这个参数表示错误对象
//错误对象也是对象,那么可以通过console.dir方法查看对象的结构
//错误对象中包含了两个属性,一个是message(错误消息)另一个是stack(错误跟踪,精准到行和列)
console.dir(e);
}
//try...catch后面的语句是可以正常运行的
console.log('hello');
二、promise基本使用
Promise的用途主要是为了实现一些异步任务,当这些异步任务的结果还没有得出的时候,此时Promise对象的状态仍然为pending
-
创建promise对象(pending状态)
const p = new Promise(executor)1、Promise本质是一个构造函数(产生一个实例化对象)
2、Promise这个构造函数中需要传入一个参数,语法规定,必须要传入的,需要传入一个回调函数(executor 执行器函数
)
3、Promise构造函数中的实际参数的回调函数中还需要传递两个参数,且这两个参数仍然为回调函数
这两个回调函数名基本不会改变:resolve(当前的状态是成功的)、reject(当前的状态是失败的)
4、Promise主要为了实现异步编程(定时器、fs模块(文件写入、读取、删除…)、ajax、数据库操作方法)中提供成功/失败的结果
5、Promise实例化对象有三个状态:pending(等待中...)、fulfilled(成功的状态)、rejected(失败的状态)
6、Promise是通过其实例化对象的三个不同的状态来控制异步编程功能
7、executor执行器函数中的两个形式参数也是可选参数,可加可不加,
什么情况会添加?当如果想要改变Promise实例化对象的状态的时候是需要添加的,默认情况下Promise实例化对象的状态为pending
执行器回调函数中的两个回调函数作用:(resolve,reject)=>{}
- reject的作用就是把Promise的状态从pending置为rejected,将实参设置到这个属性PromiseResult中,这样在then中就能捕捉到reject的回调函数
- resolve的作用就是把Promise的状态从pending置为resolved,将实参设置到这个属性PromiseResult中,这样在then中就能捕捉到resolve的回调函数
const p = new Promise((resolve,reject)=>{
//在回调函数中启动异步任务
setTimeout(()=>{
if(成功){
resolve(实参);
}else{
reject(实参);
}
},2000)
})
- 实例对象调用Promise原型中的then方法来完成对结果的处理
p.then((value)=>{
//成功
},(reason)=>{
//失败
})
三、Promise的状态改变
- pending变为fulfilled
- pending变为rejected
说明:只有这2种,且一个promise对象只能改变一次状态,状态一经改变,不可逆转
无论变为成功还是失败,都会有一个结果数据
成功的结果数据一般称为value,失败的结果数据一般称为reason
四、Promise实例对象的两个属性
-
PromiseState
此属性为promise对象的状态属性。
- fulfilled:成功的状态
- rejected:失败的状态
- pending:初始化的状态
【注】状态只能由pending->fulfilled 或者是 pending->rejected
-
PromiseResult
此属性为promise对象的结果值(resolve以及reject函数的形参值)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q8uod8Ow-1686052789729)(null)]
五、node中的promisify
- promisify (只能在 NodeJS 环境中使用)
- promisify 是 util 模块中的一个方法 util 是 nodeJS 的内置模块
- 作用: 返回一个新的函数, 函数的是 promise 风格的.
const util = require('util');
const fs = require('fs');
//promisify这个方法中需要传入一个以回调函数中是错误对象为优先的方法名
const mineReadFile = util.promisify(fs.readFile);
mineReadFile('./resource/2.html').then(value => {
console.log(value.toString());
}, reason => {
console.log(reason);
});
六、then 方法
then:指定用于得到成功value的成功回调和用于得到失败reason的失败回调,Promise的实例化对象调用Promise原型属性身上的then方法也是有返回值的,返回一个新的Promise对象
- 成功的状态:执行第一个回调函数
- 失败的状态:执行第二个回调函数
then方法返回一个Promise对象,它的的返回状态值的判断:
1、如果返回的是非promise的任意值, 新promise变为
fulfilled
, PromiseResult为返回的值
,如果没有retuen 返回值 PromiseResult为undefined
2、如果返回的是另一个新promise, 此promise的结果就会成为新promise的结果
(当下这个新的Promise对象的状态将决定于then方法返回的Promise对象的状态,结果值亦然)
3、如果抛出异常,新promise变为rejected, reason为抛出的异常
const p = new Promise((resolve,reject)=>{
resolve('ok');
});
let result = p.then(value=>{
1、throw '错误信息';// 1抛出异常 错误
2、return 100; // 值可以是字符串、数字、boolean、null、undefined、数组、对象都变为PromiseResult的结果
3、return new Promise((resolve,reject) => {
// resolve();
// reject();
// throw 404;
result的结果 取决于 此时设置的不同的状态 ,不设置的话result为pending
})
},reason=>{
console.log(reason);
});
console.log(result);
1、抛出异常的结果: PromiseState为rejected PromiseResult为抛出的错误信息
2、 非promise的任意值 结果 :PromiseState为fulfilled PromiseResult为return返回的值
3、result的结果 取决于 此时设置的不同的状态 ,不设置的话result为pending
当then方法没有传递成功/失败的回调函数的时候,那么p2的这个对象的状态和结果值???
如果then在书写的时候没有明确体现出成功/失败的时候,程序将默认补全
如果p1的状态为fulfilled的时候,then方法将补全成功回调函数为:value=>value
状态为fulfilled p1的结果值就是p2的结果值
let p1 = new Promise((resolve, reject) => {
resolve('ok');
})
// let p2 = p1.then(); 会转变为以下形式
let p2 = p1.then(value => value);
console.log(p2);
如果p1的状态为rejected的时候,then方法将补全失败回调函数为:
reason=>{throw reason}
p1的状态和结果值和p2是一致的
let p1 = new Promise((resolve, reject) => {
reject('error');
})
// let p2 = p1.then(); 会转变为以下形式
let p2 = p1.then(() => { }, reason => {
throw reason;
});
console.log(p2);
七、Promise的链式调用
通过then方法来实现链式调用
const p = new Promise((resolve,reject)=>{
//resolve('ok');
reject('error');
});
p.then(value=>{
console.log(value);
},reason=>{
console.log(reason);//error 失败状态,进入失败的函数
}).then(value=>{
console.log(value);//undefined 此时的值取决于上一个Promise对象的状态
},reason=>{
console.log(reason);
})
将 then 方法 的Promise对象的返回状态值的判断弄通这个链式调用中的值就懂了
八、终止Promise链条
通过 return new Promise((resolve, reject) => {});
返回一个pending状态的promise对象 这样后续的链式调用就不再执行
new Promise((resolve, reject) => {
resolve(111);
}).then(value=>{
console.log(value);
console.log(222);
//
// return false;
// throw '出错啦';
//有且只有一种方式 返回一个pending状态的promise对象
return new Promise((resolve, reject) => {});
}).then(value => {
console.log(333);
}).then(value => {
console.log(444);
}).catch(reason => {
console.log(reason);
});
九、Promise对象下的API方法
9.1.catch方法
功能是可以单独用来指定失败的回调函数
let p1 = new Promise((resolve, reject) => {
reject('error')
})
p1.catch(reason => {
console.log(reason); //error
})
catch方法也可以和then方法连用
当如果then方法可以catch方法连用的时候,并且then里面也有失败的回调函数的时候,具体是否还会向下执行catch
取决于then方法返回的那个新的Promise实例化对象的状态是否是失败的,因为catch方法是专门用于指定失败状态的这么一个方法
如果是失败的,会执行catch,反之不会
let p1 = new Promise((resolve, reject) => {
reject('error')
})
p1.then(value => {
console.log(value)
}, reason => {//进入到失败的回调
// console.log(reason)
return new Promise((resolve, reject) => {
reject('错误...')
})
}).catch(reason => {//通过返回值进入到catch
console.log(reason); //错误...
})
异常(错误)穿透
当如果有多个需要执行的成功时的回调函数,可以不需要每一次都写失败回调,可以统一最后利用catch
当如果promise对象的状态为reject的话,会一直向下穿透直到catch方法
let p1 = new Promise((resolve, reject) => {
reject('error')
})
p.then(value=>{
console.log(value);
}).then(value=>{
console.log(value);
}).catch(reason=>{
console.log(reason);//error
})
catch的返回值的用法和then是一样的 catch方法返回一个Promise对象,它的的返回状态值和then()方法是一样的
let p1 = new Promise((resolve, reject) => {
reject('error')
})
let p2 = p1.catch(reason => {
console.log(reason); //error
})
console.log(p2) //Promise对象
9.2 resolve方法
创建一个成功状态的Promise实例化对象
- 情况1:当如果resolve方法传递的为非Promise实例化对象的时候,
则p1这个对象的状态为fullfilled,结果值为resolve方法的实际参数值
let p1 = Promise.resolve(100);
console.log(p1);
- 情况2:当resolve方法传递的是promise实例化对象的时候,
p2的状态和结果值完全取决于resolve方法的参数中的promise对象的状态和结果值
let p2 = Promise.resolve(new Promise((resolve, reject) => {
resolve('success');
}))
console.log(p2) //fulfllted 状态 值为success
9.3reject方法
返回的结果始终为失败的Promise对象
Promise.reject(值) 无论值是什么类型 都将已错误的值返回
let p1 = Promise.reject(100);
console.log(p1); // Promise对象 失败状态 值为100
//reject的结果值仍然是reject这个方法的实际参数值
let p1 = Promise.reject(new Promise((resolve, reject) => {
resolve('success');
}));
console.log(p1);// Promise对象 失败状态 值为传递的参数这个新的promise 看下图输出
9.4 all方法
作用:针对于多个Promise的异步任务进行处理
接收的参数:参数类型是一个数组,数组里面放的是promise的实例化对象
返回值:promise对象,状态由promise数组中的对象状态
决定
- 若每个对象状态
都为
成功,则返回的promise对象状态为成功,
成功的结果值为每个promise对象成功结过值组成的数组
- 不论有几个失败状态的对象 若
任意一个对象
状态为失败,则返回的promise对象状态为失败,
失败的结果值为发现的第一个失败的promise对象的结果值
(以最快返回的第一个失败)
最终的请求时间是所有请求中耗时最长的请求所用的时间
let p1 = new Promise((resolve, reject) => {
resolve('ok');
})
let p2 = Promise.resolve('success');
let p3 = Promise.resolve('okk');
let result = Promise.all([p1, p2, p3])
console.log(result);
10.5 race方法
Promise.race() race 赛跑的意思
参数: promise 数组
返回结果: promise 对象
状态由『最先改变状态的 promise对象』决定
结果值由 『最先改变状态的 promise对象』决定
race方法是需要看哪一个Promise对象的状态已经不再是pending了,
不管是fulfilled还是rejected,只要修改了则修改的这个对象的状态和结果值直接就是arr的状态和结果值(最先出现结果的值就会输出)
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);// 成功状态的 success p1 有定时器所有慢 p2 先输出
10.6 Promise.allSettled()
allSettled方法
参数仍然为promise 数组数组
返回的也是一个Promise实例化对象,其中包括两个状态,一个是fulfilled,一个是rejected
Promise.allSettled()方法,用来确定要一组异步操作是否都结束了(不管成功或失败)。
状态是fulfillesd ,值是以对象的形式返回每一项的状态和值 组成的数组
所以,它的名字叫"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>
10.7 Promise.any()
参数还是数组,数组中的内容是Promise实例化对象
只要参数实例有一个变成fulfilled状态,包装实例就会变成fulfiilled状态;
如果所有参数实例都变成rejected,包装实例就会变成rejected状态。
Promise.any()跟Promise.race()方法很像,但是有一点不同,
就是Promise.any()不会因为某个Promise变成rejected状态而结束,
必须等到所有参数Promise变成rejected状态才会结束。
10.8 Promise.finally()
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')
})
十、async和await
async/await 是ES7提出的基于Promise的解决异步的最终方案。
10.1 async函数
async是一个加在函数前的修饰符,被async定义的函数会默认返回一个Promise对象resolve的值。
因此对async函数可以直接then,返回值就是then方法传入的函数。
async函数的返回值是一个Promise对象,这个Promise对象的状态到底是成功还是失败,取决于return后面值的类型
如果值类型为基本数据类型/引用数据类型, 则返回的Promise对象的状态为成功
如果值类型为promise实例化对象的话,则状态和返回的这个对象的状态有关联,状态值也是一样的
// async基础语法
async function fun0(){
console.log(1);
return 1;
}
fun0().then(val=>{
console.log(val) // 1,1
})
async function fun1(){
console.log('Promise');
return new Promise(function(resolve,reject){
resolve('Promise')
})
}
fun1().then(val => {
console.log(val); // Promise Promise
}
//声明一个async函数
async function main() {
console.log('async function');
//情况1:返回非promise对象数据
return 'hahaha';
//情况2:返回是promise对象数据
/* return new Promise((resolve, reject) => {
// resolve('ok');
reject('error');
}) */
//情况3:抛出异常
// throw new Error('出错啦!!!');
}
let result = main().then(value => {
console.log(value);
});
console.log(result);
10.2 await表达式
await 也是一个修饰符,只能放在async定义的函数内。可以理解为等待。
await 修饰的如果是Promise对象,可以获取Promise成功状态的结果值,且取到值后语句才会往下执行;
如果不是Promise对象:把这个非promise的东西当做await表达式的结果。
await后面是Promise成功状态的结果值
await后面如果是一个失败的Promise对象,则结果值需要通过使用try…catch来捕获得到
注意事项
- await必须写在async函数中,但是async函数中可以没有await
- 如果await的promise失败了,就会抛出异常,需要通过try…catch捕获处理
async function fun(){
let a = await 1;
let b = await new Promise((resolve,reject)=>{
setTimeout(function(){
resolve('setTimeout')
},3000)
})
let c = await function(){
return 'function'
}()
console.log(a,b,c)
}
fun(); // 3秒后输出: 1 "setTimeout" "function"
function log(time){
setTimeout(function(){
console.log(time);
return 1;
},time)
}
async function fun(){
let a = await log(1000);
let b = await log(3000);
let c = log(2000);
console.log(a);
console.log(1)
}
fun();
// 立即输出 undefined 1
// 1秒后输出 1000
// 2秒后输出 2000
// 3秒后输出 3000
async function main() {
//1、如果await右侧为非promise类型数据
var rs = await 10;
var rs = await 1 + 1;
var rs = await "非常6+7";
//2、如果await右侧为promise成功类型数据
var rs = await new Promise((resolve, reject) => {
resolve('success');
})
//3、如果await右侧为promise失败类型数据,需要借助于try...catch捕获
try {
var rs = await new Promise((resolve, reject) => {
reject('error');
})
} catch (e) {
console.log(e);
}
}
main();
// 使用async/await获取成功的结果
// 定义一个异步函数,3秒后才能获取到值(类似操作数据库)
function getSomeThing(){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve('获取成功')
},3000)
})
}
async function test(){
let a = await getSomeThing();
console.log(a)
}
test(); // 3秒后输出:获取成功
async 用来修饰函数
async 修饰过的函数,函数的返回值变成了 promise,这个promise我们叫做【async函数的promis】
问: 【async函数的promis】 成功失败由什么来决定? — 由函数的return来决定
1. return 一个非promise值得时候,【async函数的promis】一定是成功的,promise的值是 return值
2. return 一个promise值,【async函数的promis】由这个return的promise来决定
return的promise是成功的,【async函数的promis】也是成功的
return的promise是失败的,【async函数的promis】也是失败的
3. 函数如果抛出错误,那么【async函数的promis】也是失败的
await
await等待的意思,await必须放在async函数中
1. await 跟一个非promise值,直接得到这个结果
2. await 跟一个成功的promise,等待这个promsie执行完毕,拿到成功的值
3. await 无法跟一个失败的promise,跟一个失败的promsie,此时这行代码会立即抛错(后续代码不会执行了)
4. await 跟一个pendding状态的promsie,会一直等待这个promise出结果
十一、代码
ES5写法
(function (window) {
// executor是执行器函数
function Promise(executor) {
//构造函数中的this一定是指向其实例化对象的
// 定义实例属性state,初始值为pending
this.PromiseState = 'pending';
// 定义实例属性result,初始值为undefined
this.PromiseResult = undefined;
// 定义实例属性callbackFun,起始值为一个数组
this.callbackFun = [];
/* [
{onResolved:function(){},onRejected:function(){}},
{onResolved:function(){},onRejected:function(){}},
{onResolved:function(){},onRejected:function(){}}
] */
// 定义resolve函数
const _resolve = value => {
// 当状态已经被更改过,不允许再次更改
if (this.PromiseState !== 'pending') return;
//在修改状态之前需要考虑一件事,Promise实例化对象的状态是否仍然是pending
//如果不是pending了,不管是fulfilled还是rejected,就不会执行后面的代码
// 将状态更改为成功(fulfilled)
this.PromiseState = 'fulfilled';
// 成功值为value
this.PromiseResult = value;
//运行执行器函数内部的异步代码
// console.log(this.callbackFun)
this.callbackFun.forEach(item => {
item.onResolved();
})
}
// 定义reject函数
const _reject = reason => {
// 当状态已经被更改过,不允许再次更改
if (this.PromiseState !== 'pending') return;
// 将状态更改为失败
this.PromiseState = 'rejected';
// 将result设置为reason
this.PromiseResult = reason;
this.callbackFun.forEach(item => {
item.onRejected();
})
}
try {
executor(_resolve, _reject);
} catch (err) {
_reject(err);// 状态更改为失败,值为异常信息
}
}
// Promise.prototype.then = function () { }
//对象间的合并
//第二个参数(源对象)向第一个参数(目标对象)合并
//合并的时候,如果两个对象中有相同的属性,则后者会覆盖前者
Object.assign(Promise.prototype, {
// onResolved:成功回调
// onRejected:失败回调
then(onResolved, onRejected) {
//判断当then方法里面没有传递两个实际参数的回调函数的时候,需要添加默认值
//instanceof是判断一个值是否所属于某一个构造函数的实例化对象
//补充成功回调函数
if (!(onResolved instanceof Function)) {
onResolved = value => value; // value=>{return value}
}
//补充失败回调函数
if (!(onRejected instanceof Function)) {
onRejected = reason => {
throw reason;
};
}
return new Promise((resolve, reject) => {
const _common = function (callback) {
setTimeout(() => {
try {
// value是成功回调的返回值
const value = callback(this.PromiseResult);
// 判断value是不是通过Promise实例化出来的(判断value是否为Promise实例)
if (value instanceof Promise) {
value.then(v => {
resolve(v);
}, r => {
reject(r);
});
}
else {
// 不是Promise实例,将返回的Promise状态设置为成功,值为value
resolve(value);
}
} catch (err) {
// 有异常,将返回Promise的状态更改为失败,值为err
reject(err);
}
})
}
// 状态成功调用onResolved
//这两种状态的改变相当于是同步代码的直接改变
// p1的状态为成功
if (this.PromiseState === 'fulfilled') {
_common.call(this, onResolved);
} else if (this.PromiseState === 'rejected') {
_common.call(this, onRejected);
} else {
//当异步任务没有执行完毕的时候,此时Promise实例化对象的状态为pending
//但是在pending的期间最终结果到底是fulfilled还是rejected,都有可能
//可以在当前Promise实例化对象身上添加一个回调函数的属性,用来存储两个回调(成功的回调,失败的回调)
this.callbackFun.push({
onResolved: _common.bind(this, onResolved),
onRejected: _common.bind(this, onRejected)
})
}
})
},
catch(onRejected) {
//既然catch方法和then方法做的功能是一致的,那么我们没必要将代码在复制粘贴一份,而选择直接调用then方法
// console.log(onRejected);
return this.then(undefined, onRejected);
}
})
//Promise对象下的方法添加
// console.dir(Promise);
Promise.resolve = function (value) {
return new Promise((resolve, reject) => {
//判断value的类型到底是不是一个Promise对象
if (value instanceof Promise) {
// console.log('实例化对象', value);
// value.then(v => {
// resolve(v);
// }, r => {
// reject(r);
// })
//简写的形式
value.then(resolve, reject);
} else {
resolve(value);
}
})
}
Promise.reject = function (value) {
return new Promise((resolve, reject) => {
//直接将Promise实例化对象状态更改成rejected
reject(value);
})
}
Promise.all = function (value) {
// 定义一个变量,用来计数(计成功的Promise的数量,到时候和数组的数量做对比)
let index = 0;
//定义一个数组,数组用来装如果all方法里面都是成功的Promise对象的结果值
//new Array(数字):表示预设数组长度
let arr = new Array(value.length); // [??]
return new Promise((resolve, reject) => {
value.forEach((item, i) => {
// console.log('数组的每一项:', item);
// console.log('数组的下标:', i)
item.then(v => {
//只要有一个成功的Promise实例化对象,就让计数器+1
index++;
arr[i] = v;
if (index === value.length) {
//只要计数器数值和all方法中的长度一致,则证明数组中每一个元素都是成功的Promise对象
resolve(arr);
}
}, r => {
//只要有失败,状态将立即更改
reject(r);
})
})
})
}
Promise.race = function (value) {
return new Promise((resolve, reject) => {
value.forEach(item => {
//从数组中的第一个Promise对象开始循环,只要能够进入到then的回调函数之中,不管是哪一个回调函数
//说明此时Promise对象的状态一定不为pending,所以不管是成功还是失败,直接修改状态
item.then(v => {
resolve(v);
}, reason => {
reject(reason)
})
})
})
}
window.Promise = Promise;
})(window);
class写法
(function (window) {
//声明类
class Promise {
constructor(executor) {
//this指向的是Promise这个类的实例化对象
this.PromiseState = 'pending';
this.PromiseResult = undefined;
//当执行器函数内部的代码为异步代码的时候
this.callbackFun = [];
// 定义resolve函数
const _resolve = value => {
// 当状态已经被更改过,不允许再次更改
if (this.PromiseState !== 'pending') return;
//在修改状态之前需要考虑一件事,Promise实例化对象的状态是否仍然是pending
//如果不是pending了,不管是fulfilled还是rejected,就不会执行后面的代码
// 将状态更改为成功(fulfilled)
this.PromiseState = 'fulfilled';
// 成功值为value
this.PromiseResult = value;
this.callbackFun.forEach(item => {
item.onResolved();
})
}
// 定义reject函数
const _reject = reason => {
// 当状态已经被更改过,不允许再次更改
if (this.PromiseState !== 'pending') return;
// 将状态更改为失败
this.PromiseState = 'rejected';
// 将result设置为reason
this.PromiseResult = reason;
this.callbackFun.forEach(item => {
item.onRejected();
})
}
try {
executor(_resolve, _reject);
} catch (err) {
_reject(err);// 状态更改为失败,值为异常信息
}
}
then(onResolved, onRejected) {
//判断当then方法里面没有传递两个实际参数的回调函数的时候,需要添加默认值
//instanceof是判断一个值是否所属于某一个构造函数的实例化对象
//补充成功回调函数
if (!(onResolved instanceof Function)) {
onResolved = value => value; // value=>{return value}
}
//补充失败回调函数
if (!(onRejected instanceof Function)) {
onRejected = reason => {
throw reason;
};
}
return new Promise((resolve, reject) => {
const _common = function (callback) {
setTimeout(() => {
try {
// value是成功回调的返回值
const value = callback(this.PromiseResult);
// 判断value是不是通过Promise实例化出来的(判断value是否为Promise实例)
if (value instanceof Promise) {
value.then(v => {
resolve(v);
}, r => {
reject(r);
});
}
else {
// 不是Promise实例,将返回的Promise状态设置为成功,值为value
resolve(value);
}
} catch (err) {
// 有异常,将返回Promise的状态更改为失败,值为err
reject(err);
}
})
}
// 状态成功调用onResolved
//这两种状态的改变相当于是同步代码的直接改变
// p1的状态为成功
if (this.PromiseState === 'fulfilled') {
_common.call(this, onResolved);
} else if (this.PromiseState === 'rejected') {
_common.call(this, onRejected);
} else {
//当异步任务没有执行完毕的时候,此时Promise实例化对象的状态为pending
//但是在pending的期间最终结果到底是fulfilled还是rejected,都有可能
//可以在当前Promise实例化对象身上添加一个回调函数的属性,用来存储两个回调(成功的回调,失败的回调)
this.callbackFun.push({
onResolved: _common.bind(this, onResolved),
onRejected: _common.bind(this, onRejected)
})
}
})
}
catch(onRejected) {
//既然catch方法和then方法做的功能是一致的,那么我们没必要将代码在复制粘贴一份,而选择直接调用then方法
// console.log(onRejected);
return this.then(undefined, onRejected);
}
static resolve = function (value) {
return new Promise((resolve, reject) => {
//判断value的类型到底是不是一个Promise对象
if (value instanceof Promise) {
// console.log('实例化对象', value);
// value.then(v => {
// resolve(v);
// }, r => {
// reject(r);
// })
//简写的形式
value.then(resolve, reject);
} else {
resolve(value);
}
})
}
static reject = function (value) {
return new Promise((resolve, reject) => {
//直接将Promise实例化对象状态更改成rejected
reject(value);
})
}
static all = function (value) {
// 定义一个变量,用来计数(计成功的Promise的数量,到时候和数组的数量做对比)
let index = 0;
//定义一个数组,数组用来装如果all方法里面都是成功的Promise对象的结果值
//new Array(数字):表示预设数组长度
let arr = new Array(value.length); // [??]
return new Promise((resolve, reject) => {
value.forEach((item, i) => {
// console.log('数组的每一项:', item);
// console.log('数组的下标:', i)
item.then(v => {
//只要有一个成功的Promise实例化对象,就让计数器+1
index++;
arr[i] = v;
if (index === value.length) {
//只要计数器数值和all方法中的长度一致,则证明数组中每一个元素都是成功的Promise对象
resolve(arr);
}
}, r => {
//只要有失败,状态将立即更改
reject(r);
})
})
})
}
static race = function (value) {
return new Promise((resolve, reject) => {
value.forEach(item => {
//从数组中的第一个Promise对象开始循环,只要能够进入到then的回调函数之中,不管是哪一个回调函数
//说明此时Promise对象的状态一定不为pending,所以不管是成功还是失败,直接修改状态
item.then(v => {
resolve(v);
}, reason => {
reject(reason)
})
})
})
}
}
window.Promise = Promise;
})(window)