一、Promise前言
(1):函数对象和实例对象
函数对象:将函数作为对象来使用,简称函数对象 (就是直接调用函数原型对象上面的属性或方法)
实例对象:new函数产生一个对象,简称对象!
注意点:?() — ?为函数; ?.call() —?为函数对象!
function Fn() { //Fn为函数
}
let fn = new Fn(); //Fn为构造函数 fn为函数的实例对象(对象)
console.log(Fn.prototype); // Fn为函数对象
Fn.call(); //call()都是Fn的实例,定义渣原型上,这边Fn为函数对象
$('#box');//jq函数
$.get('.box');//jq函数对象
(2):回调函数
1:同步回调 — 立即执行,完全执行完才结束,不会放入回调队列中
eg:数组遍历相关的回调函数,Promise的excutor函数
2:异步回调 — 不会立即执行,会放入回调队列中
eg:定时器,ajax,promise的成功或失败
如何判断是同步函数还是异步函数?
就是在函数后面添加一个输出(log),看看这个输出是先输出还是后输出,先输出的为异步函数,后输出的为同步函数!
//1:同步回调函数
let arr = [1, 3, 5];
arr.forEach(item => { //遍历回调为同步回调函数
console.log(item);
})
console.log('forEach之后');
//结果 1 3 5 forEach之后 证明这一个函数为同步函数!
//2:异步函数
setTimeout(() => { //这个是异步回调,会放入回调队列中稍后执行
console.log("setTimeout callback");
})
console.log("setTimeout 之后");
//结果: setTimeout 之后 setTimeout callback
(3):错误类型
1:错误类型
Error:所有错误的父类型
ReferenceError:引用变量不存在 (经常遇到)
TypeError:数据类型不正确 (经常遇到)
RangeError:数值不在所在范围内
SyntaxError:语法错误
2:错误处理
捕捉错误:try …catch
抛出错误:throw … error (需要自己再捕获异常 看看出现什么错误)
3:错误对象
message属性:错误相关信息
stack属性:函数调用栈记录
错误类型:
// 1:ReferenceError:引用变量不存在
console.log(a); //引用变量错误 Uncaught ReferenceError :a is not defined at
// 2:TypeError:数据类型不正确
// let num = null;
// console.log(num.xxx);
// let b = {}
// b.xxx();
// 类型错误(num为null,而num.xxx需要num为对象才能调用)Uncaught TypeError: Cannot read property 'xxx' of null
//3: RangeError:数值不在所在范围内
// function fn() {
// fn();
// }
// fn();
//递归函数,回调次数超出了所在范围 Uncaught RangeError: Maximum call stack size exceeded
//4: SyntaxError:语法错误
// let abc = """";//语法错误 SyntaxError
捕获异常和抛出异常
// 因为出现错误后,程序不能继续执行了,需要对错误进行处理,常见的有
// 1:捕获错误 try ... catch
// try {
// let b;
// console.log(b.xxx());
// } catch (error) {
// console.log(error);
// console.log(error.message); //Cannot read property 'xxx' of undefined
// console.log(error.stack); //TypeError: Cannot read property 'xxx' of undefined
// }
// 注意点:try来捕捉错误,catch来显示捕捉的错误! error里面有两个属性,message---提示信息 stack---提示信息和类型错误提示!
//程序还能继续向下执行!
// 2:抛出错误
function something() {
if (Date.now() % 2 === 1) {
console.log("当前时间为奇数,执行任务");
} else { //如果当前时间为偶数抛出异常,有调用者来处理1
throw new Error('当前时间为偶数,不能执行任务');//抛出异常,需要新建一个Error()---这边是所有错误的父类型1
//注意点:假如这边直接捕获,就不用try来捕获了
}
}
//来捕获异常
try {
something()
} catch (error) {
console.log(error.message);
}
二、Promise基础
(1):Promise是什么?和基本使用
1:Promise是什么
抽象解析:
01:Promise是JS中进行异步编程的新的解决方案! (旧的方案是纯回调函数形式 --- 产生回调地狱!)
具体解析:
02:从语法上看Promise是一个构造函数! (new Promise ---执行构造函数,返回实例对象)
03:从功能上看,Promise对象用来封装了一个异步操作最终完成(或失败),及其结果
2:Promise状态
初始状态为pending ---未确定的
01:pending变为fulfilled(resolve) ---满足阶段 ---会回调then()
02:pending变为rejected(reject) ---未决定,履行,拒绝阶段 --- 会回调catch()
Promise的状态只有上述两种状态切换,而且Promise对象只能改变一次
无论成功还是失败,都会返回一个数据,成功的为value,失败的为reason
3:执行流程
创建和执行流程
第一步:创建一个Promise构造函数,返回一个promise对象,里面传入的是一个执行器函数(同步函数)
第二步:执行器函数里面有两个参数,参数1为成功的回调,参数2为失败的回调,判断成功与失败,里面返回数据(成功的结果或失败的结果或其他值)
第三步:再.then方法中判断里面的是否是函数,若是函数就执行(函数的话,证明是Promise对象,于是可以调用.then方法),否则就忽略。
第四步:再.then方法中,onFulfilled为函数就调用resolve('-成功的数据') 里面的数据,失败也是同理回调,输出数据!
注意点1:resolve函数的作用,就是把promise对象的状态从“未完成”变为成功,(即peding-resolved),在异步操作成功时调用,并且将异步操作结果,作为参数传递到下一个Promise.then方法作为条件。
注意点2:reject函数的作用,就是把promise对象的状态从“未完成”变为失败,(即peding-rejected),在异步操作失败时调用,并且将异步操作结果,作为参数传递到下一个Promise.then方法作为条件。
注意点3:Promise实例生成后,可以使用then方法分别指定resolve状态和rejected状态的回调函数!
注意点4:一个 promise 必须提供一个 then 方法以访问其当前值、终值和据因
promise 的 then 方法接受两个参数,promise.then(onFulfilled, onRejected),这两个都是可选参数
4:Promise的基本使用
//1:创建一个Promise对象
const p = new Promise((resolve, reject) => {
console.log(0); //执行器函数,为同步函数,优先执行
//2:异步任务操作
setTimeout(() => {
let time = Date.now();
if (time % 2 === 0) { //偶数成功,奇数失败
resolve(1) //该Promise成功时,结果值为1,代表包裹这个resolve(1)的Promise的返回的结果为Promise对象和成功值为1
} else {
reject(2) //该Promise失败时,结果值为2
}
}, 1000)
})
p.then(
value => {
console.log("onFulfill1()", value); //上面的Promise成功,调用then方法的时,把成功值当做参数传递进来,于是value为1
},
reason => {
console.log("onRejected1()", reason); //上面的Promise失败,调用then方法的时,把成功值当做参数传递进来,于是value为2
}
)
//结果:0 , 还有onRejected1() 2 或onFulfill1() 1
(2):为什么使用Promise
1:指定的回调函数更加灵活:
旧的:必须在启动异步任务前指定回调函数
promise:启动异步任务 =>返回promise对象 =>给promise对象绑定回调函数
而promise是一般是启动异步任务之后,才指定回调函数!也可以等有了结果,在指定!
2:promise支持链式调用的,可以解决回调地狱!
什么是回调地狱?回调函数嵌套调用(一个异步操作嵌套一个异步操作。。。),外部嵌套函数异步的执行结果为内层的嵌套函数的执行条件
回调地狱的缺点? 阅读性差,不便于处理异常
解决方案1:Promise链式调用;
但是async/await更为简洁,是最好的方式!
注意点:
使用promise的话,就封装一个异步操作的函数,返回一个promise对象,
一个Promise对应一个异步任务(一旦返回一个promise对象,就说明了启动了一个异步任务)
// 2.1,回调地狱
doSomething(function (result) {
doSomethingElse(result, function (newResult) {
doThirdThing(newResult, function (finalResult) {
console.log('Got the final result: ' + finalResult)
}, failureCallback)
}, failureCallback)
}, failureCallback)
//多个串联的异步操作:也就是说第一个弄完后才弄第二个
// 2.2.使用 promise的链式调用解决回调地狱
dosomething()
//dosomething() 假如为一个封装的异步操作函数,返回的是promise对象,就是启动了异步任务! .then()为成功的回调,result为收到的结果
.then(function (result) {//result为第一个promise返回的数据
return dosomethingElse(result) //result为Promise.then的返回的结果(成功或失败,返回值为result),然后作为条件传入第二个回调函数(dosomethingElse)中作为条件,调用了第二个异步任务了
})
.then(function (newResult) { //newResult为第二个回调函数处理Promise.then的结果
return doThirdThing(newResult) //作为参数传入,并且 调用了第三个异步任务了
})
.then(function (finalResult) { //这边的.then()为第三个异步任务的回调结果! --finalResult
console.log('Got the final result:' + finalResult)
})
.catch(failurecallback)
//优点:失败的回调都直接放置在最后,中间都是成功的回调! 异常传递(中间任何一环出错,这里都会可以打印出来)
//2.2实例代码
//1:创建一个Promise对象
const p = new Promise((resolve, reject) => {
console.log(0); //执行器函数,为同步函数,优先执行
//2:异步任务操作
setTimeout(() => {
let time = Date.now();
if (time % 2 === 0) { //偶数成功,奇数失败
resolve(1) //该Promise成功时,结果值为1,代表包裹这个resolve(1)的Promise的返回的结果为Promise对象和成功值为1
} else {
reject(2) //该Promise失败时,结果值为2
}
}, 1000)
}).then(
value => {//value为第一个Promise的成功值或失败值,作为参数传递进来到箭头函数
console.log("onFulfilled1()", value);
//return new Promise((resolve, reject) => {
//resolve(1)
//})
},
reason => {
console.log("onRejected1()", reason);
}
)
//结果为: 0 onFulfilled1() 1,要么 0 onRejected1() 2
// 2.3 async/await: 回调地狱的终极解决方案(相比较promise,async/await从源码上来看没有回调函数)
async function request() {
try {
const result = await doSomething() //这一段代码必须成功后,才会执行下面的代码,以此类推
const newResult = await doSomethingElse(result)
const finalResult = await doThirdThing(newResult)
console.log('Got the final result' + finalResult)
} catch (reason) {
failureCallback(reason)
}
}
(3):Promise的API
1:promise语法糖
//需求:产生一个成功值为01的promise对象,并且调用其数据输出
// 01:采用语法糖定义一个promise对象
const p01 = Promise.resolve(01);
p01.then(value => {
console.log(value);
})
//:02:采用语法糖+链式编程
Promise.resolve(02).then(value => {
console.log(value);
})
2:Promise.all方法
返回的是一个promise对象,里面的为promise对象组成的数组形式或者可迭代的String
const p1 = Promise.resolve(1);
const p2 = Promise.resolve(2);
const p3 = Promise.reject(3);
假如三个异步任务都是成功的时候,才能获取到数据或继续向下执行,那么使用Promise.all方法极好! 有一个失败就会失败!
//const pAll = Promise.all([p1, p2, p3]); //里面参数为数组形式,p1-p3都为promise对象 结果,由于3为失败,调用onReject()执行reason()
const pAll = Promise.all([p1, p2]);
pAll.then(
values => {
console.log('onFulfill()', values);
},
reason => {
console.log('onReject()', reason);
}
)
3:Promise.race方法
Promise.race()方法,返回一个promise,一旦迭代器中的某个promise解决或拒绝,返回的 promise就会解决或拒绝 看谁先执行最快结束,就看它的结果!
const p1 = Promise.resolve(1);
const p2 = Promise.resolve(2);
const p3 = Promise.reject(3);
// const pRace = Promise.race([p1, p2, p3]); //结果为:race onFulfill() 1 因为都没有设置延迟,先执行1的 成功
const pRace = Promise.race([p3, p2, p1]); //结果为:race onReject() 3 因为都没有设置延迟,先执行3的 失败
pRace.then(
values => {
console.log("race onFulfill()", values);
},
reason => {
console.log('race onReject()', reason);
}
)
(4):Promise几个关键问题解析
1:Promise的状态
1:resolve --- pending变为resolveed(确定),调用成功
2:rejecte --- pending变为rejected(失败),调用失败
3:抛出异常 --- 抛出异常后就是peding变为rejected
2:一个Promise指定多个成功、失败回调函数,都会调用吗?
当promise改变状态的时候,都会调用!
//1:创建一个promise对象 --- 里面传入一个执行器函数(同步的回调函数) 执行器函数里面有两个参数(resolve,reject)也是回调函数!
const p1 = new Promise((resolve, reject) => {
throw new Error;
// throw 3; //抛出异常
})
p1.then( //指定回调函数
value => {
console.log();
},
reason => {
console.log('reason', reason);
}
)
p1.catch(
reason => {
console.log('reason2', reason);
}
)
//结果: reason Error reason2 Error
3:改变promise状态还有指定回调函数是谁先谁后?
(1)都有可能,正常情况下,先指定回调函数后在改变状态,但也可以先改变状态在指定回调函数
(2)如何先改变状态再指定回调函数?
01方法:在执行器函数中先调用resolve()/reject()
02方法: 延迟更长时间才调用!
(3)什么时候才能得到数据?
01:如果先指定回调函数,那么当状态发生改变的时候,回调函数就被调用并且得到数据
02:如果先改变状态,那当指定回调函数时,回调函数被调用后,得到数据
注意点:.then方法里面的value,reason为异步回调函数!
先指定回调函数,再改promise状态
//先指定回调函数,再改promise状态
new Promise((resolve, reject) => {
//执行异步任务
setInterval(() => { //由于异步任务,有延迟1S,再改变状态(同时指定数据),异步执行回调函数
resolve(1);
}, 1000)
}).then( //先指定回调函数 保存当前指定回调函数!
value => { //注意点:这是异步回调函数
console.log('onFulfilled', value);
},
reason => {
console.log('onRejected', reason);
}
)
先改变promise状态,再指定回调函数
//方式1:
new Promise((resolve, reject) => {
resolve(1); //先改变状态(同时指定数据)
}).then( //再指定回调函数,异步执行回调函数(成功还是失败的回调)
value => {
console.log('value', value);
},
reason => {
console.log('reason', reason);
}
)
// 方式2
const p1 = new Promise((resolve, reject) => {
//执行异步任务
setInterval(() => { //先改变状态(同时指定数据) 因为then延迟时间比这边长
resolve(1);
}, 1000)
})
setTimeout(() => {
p1.then( //再指定回调函数,异步执行回调函数(成功还是失败的回调)
value => {
console.log('onFulfilled', value);
},
reason => {
console.log('onRejected', reason);
}
)
}, 1100)
4:Promise.then()返回的是一个新的promise(对象)的结果状态由谁决定?
(1)简单表达:由.then方法指定的回调函数执行的结果决定!(就是调用.then方法的promise实例)
(2)详细表达:
01:如果抛出异常,新的promise变为rejected,reason为抛出的异常
02:如果返回的是为promise的任意值,新的promise变为resolved,value值为返回的值
03:如果返回一个新的promise对象,此promise的结果就会成为新的promise的结果!
//1:请问下面的输出结果为?
new Promise((resolve, reject) => {
resolve(1);
// reject(1);
}).then( //由于上面new promise函数是失败的,所以调用.then的失败函数
value => {
console.log('onFulfiled()', value); //23行
// return 2;
// return Promise.resolve(3); //返回一个成功值为3的promise实例
// return Promise.reject(4); //返回一个失败值为4的promise实例
throw 5;
},
reason => {
console.log('onRejected()', reason); //26行
}
).then( //因为.then()返回的是一个新的promise对象,才能继续链式.then(), 这边的.then调用有上一层promise函数的执行后的结果!
value => {
console.log('onFulfiled2()', value); //30行
},
reason => {
console.log('onRejected2()', reason); //33行
}
)
//当resolve(1)时 --- 结果1为:由于执行了23行和30行 onFulfiled() 1 onFulfiled2() undefined
// 解析:为何30行代码输出undefined?,这是因为这边的.then方法是上一层promise函数执行后,却没有返回任何值,也就是undefined
//若是在23行下添加一个return 2; 那么其结果将会变为onFulfiled2() 2,而非未定义! 若是return Promise.resolve(3); 那么其结果为onFulfiled2()3
//若返回的是return Promise.reject(4),结果为onRejected2() 4 若是抛出异常throw 5; 结果为:onRejected2() 5
//就是啊第一个promise执行的是成功,值为1,调用.then后,这个值1为执行结果(首先先判断成功还是失败),
// 成功时候,就调用下一个.then中成功的回调函数(里面在返回一个值或者新的promise,为调用.then的判断条件!)
//当reject(1)时 执行的是26行,还有30行 ---结果为: onRejected() 1 ,onFulfiled2() undefined
5:Promise如何串联多个操作任务?
01:promise的then()返回一个新的promise对象,可以看成.then()的链式调用
02:通过then的链式调用串联多个同步/异步任务!
new Promise((resolve, reject) => {
setTimeout(() => {
console.log('执行任务1(异步)');
resolve(1); //成功的回调,指定数据为1 ---这边是promise.then()后在输入结果,也就是任务1的结果!
// (成功的时候,调用OnFulfilled(),也就是value =>{} value就是成功的值!
}, 1000)
}).then(
value => {
console.log('任务1的结果为:', value);
console.log("执行任务2(同步)");
return 2;
}
).then(
value => {
console.log("任务2的结果为:", value);
//异步任务需要封装在一个promise对象里面,并且需要确定promise的状态(也就是resolve(3))
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('执行任务3(异步)');
resolve(3);
}, 1000)
})
}
).then(
value => {
console.log("任务3的结果为:", value);
}
)
//注意点:一旦是异步任务的就需要包裹在一个promise对象里面!
//结果:执行任务1(异步) 任务1的结果为: 1
// 执行任务2(同步) 任务2的结果为: 2
// 执行任务3(异步) 任务3的结果为: 3
6:promise的异常传透?
01:当使用promise的then链式调用时,可以在最后指定失败的回调
02:前面的任何操作异常,都会传到最后的失败的回调函数中处理!
new Promise((resolve, reject) => {
// resolve(1);
reject(1);
}).then(
value => {
console.log("onFulfilled1()", value);
return 2;
},
// resoan => {
// throw reason
// }
// reason => Promise.reject(reason) //也可以自己抛出异常
).then(
value => {
console.log("onFulfilled2()", value);
return 3;
}
).then(
value => {
console.log("onFulfilled3()", value);
return 4;
}
).catch(
reason => {
console.log("onRejected1()", reason);
}
)
//执行结果:onRejected1() 1
//执行流程:第一个promise执行的时候reject(1)失败,在调用.then方法时候,就是执行失败的回调(也就是reason =>{)},
//但是若是这边.then()没有写reason =>{。。。},里面会自动帮你补上reason =>{throw reason},然后这边的结果依然是失败状态,继续往下面传透失败的回调结果!
//注意点:反正就是一个promise对象状态为成功时(指定了数据),并且在.then方法中调用成功的回调,失败也是同理!
7:中断promise链?
01:当使用promise的链式调用时,在中间中断,不在调用后面的回调函数
02:办法:在回调函数中返回一个pendding状态的promise对象
new Promise((resolve, reject) => {
// resolve(1);
reject(1);
}).then(
value => {
console.log("onFulfilled1()", value);
return 2;
},
// resoan => {
// throw reason
// }
// reason => Promise.reject(reason) //也可以自己指定要返回的异常!
).then(
value => {
console.log("onFulfilled2()", value);
return 3;
}
).then(
value => {
console.log("onFulfilled3()", value);
return 4;
}
).catch(
reason => {
console.log("onRejected1()", reason);
// throw reason;
return Promise.reject(reason);
//这边继续链式.then方法后,需要返回失败的回调,不然就直接调用成功的!后面添加一个新的promise,状态为pedding,直接中断
// return new Promise(() => {})
}
).then(
value => {
console.log("onFulfilled3()", value);
return 4;
},
reason => {
console.log("onRejected2()", reason);
}
)
//结果:不添加什么就 onRejected1() 1, onFulfilled3() undefined 若是添加失败的回调就:onRejected1() 1 onRejected2() 1
//结果: return new Promise(() => {})-添加了 onRejected1() 1
三、自定义一个promise的各种方法解析
(1):自定义promise的准备工作
新建一个lib库用于存放自己自定义的promise.js文件
然后向外暴露promise函数,以供外面调用,这就需要使用到ES5中的立即执行函数来导出promise模块
注意点:立即执行函数传入window,是为了让promise函数暴露出来
需要在执行器函数内部定义状态,数据,还有回调函数的缓存!
01:还有需要定义一下,promise的初始状态为pending
02:给promise指定一个存储结果数据的属性
03:定义一个回调函数里面存放着可能待执行的函数(缓存回调函数)
this.callbacks = []; //每一个元素的结构:{onFulfilled(){},onRejected(){}}
04:指定执行器函数和resolve,reject函数同步执行(也就是执行器函数调用这两个函数)!
/*
自定义Promise函数模块
*/
// 使用ES5的模块化 ---立即执行函数
(function (window) {
/*
Promise构造函数
executor:执行器函数
*/
function Promise(executor) {
this.status = 'pending'; //给promise对象指定status属性,初始值为pending
this.data = undefined; //给promise指定一个存储结果数据的属性
this.callbacks = []; //每一个元素的结构:{onFulfilled(){},onRejected(){}}
function resolve(value) {
}
function reject(reason) {
}
//因为使用的时候,在executor执行器函数里面传入了两个回调函数,需要在这边定义一下!
//立即同步执行exxcutor
executor(resolve, reject);
}
/*Promise原型对象的then()
指定成功和失败的回调函数,并且返回一个新的promise对象
*/
Promise.prototype.then = function (onFulfilled, onRejected) {
}
/*Promise原型对象的catch()
指定失败的回调函数,并且返回一个新的promise对象
*/
Promise.prototype.catch = function (onRejected) {
}
/*Promise函数对象的resolve方法
返回一个指定结果成功值为value的promise
*/
Promise.resolve = function (value) {
}
/*Promise函数对象的reject方法
返回的是一个指定结果失败值为reason的promise
*/
Promise.reject = function (reason) {
}
/*Promise函数对象的all方法 all方法里面参数是promise对象组成的数组!
返回的是一个promise,只有数组中的promise都成功的时候才成功,否则有一个失败,就失败!
*/
Promise.all = function (Promises) {
}
/*Promise函数对象的race方法 race方法里面参数是promise对象组成的数组!
返回的是一个promise,其结果有数组中的promise对象,先完成的promise决定!
*/
Promise.race = function (Promises) {
}
//向外暴露Promise函数
window.Promise = Promise
})(window)
(2):对于执行器函数内部的定义
首先Promise是个函数,它需要传一个function,就是执行器函数(executor),就相当于我们使用Promise时那个new Promise(function(resolve,reject))中的function()
然后执行器函数里面有两个参数,就是resolve和reject,分别对应的是成功的回调还有失败的回调
因此执行器函数由三部分组成:分别为resolve函数,reject函数,executor同步执行函数
1:resolve函数-代表的是成功时
2:reject函数-代表是失败的时
3:executor函数-执行函数的时候,连带resolve和reject绑定在一起,先被调用执行谁
注意点:需要在resolve和reject函数里面先判断promise状态是否为pending状态,假如不是,直接结束掉,也就是return;
// 因为状态只能改变一次!,一进来就是reject(或resolve)就执行,若是pending就直接结束掉!
// Promise构造函数 executor:执行器函数
function Promise(executor) {
const that = this; //把that指向promise的that存再一个变量中,需要用的时候,就调用!
that.status = 'pending'; //给promise对象指定status属性,初始值为pending
that.data = undefined; //给promise指定一个存储结果数据的属性
that.callbacks = []; //定义一个回调函数里面存放着可能待执行的函数,每一个元素的结构:{onFulfilled(){},onRejected(){}}
function resolve(value) {
//00:需要先判断 当前状态是否是pending,如果不是直接结束掉
if (that.status != 'pending') {
return
}
//01:将状态改为resolved
that.status = 'resolved'
//保存value数据
that.data = value;
//:02:如果有待执行callback函数,立即异步执行回调函数onFulfilled()(丢到任务队列中)
if (that.callbacks.length > 0) {
setTimeout(() => { //03:放入队列中,执行所有成功的回调
that.callbacks.forEach(callbacksObj => { //遍历出回调函数数组中是否有成功的回调函数
callbacksObj.onFulfilled(value); //给成功的回调函数指定成功的结果!
});
})
}
}
function reject(reason) {
//需要先判断 当前状态是否是pending,如果不是直接结束掉
if (that.status != 'pending') {
return
}
that.status = "rejected"
that.data = reason;
if (that.callbacks.length > 0) {
setTimeout(() => {
that.callbacks.forEach(callbacksObj => {
callbacksObj.onRejected(reason)
})
}, 1000)
}
}
//因为使用的时候,在executor执行器函数里面传入了两个回调函数,需要在这边定义一下!
//立即同步执行exxcutor
try {
executor(resolve, reject);
} catch (error) { //然后执行器抛出异常,那么就调用reject失败函数
reject(error)
}
}
(3):对于promise.prototype.then()函数的定义
Promise原型对象的then()
功能:返回一个新的promise对象,并且指定成功和失败的回调函数,
01:返回一个新的prmise对象,使用new Promise里面传入执行器函数
02:并且指定成功和失败的回调函数,那么需要在执行器函数里面
03:在执行器函数里面,就行需要根据promise的状态处于哪个状态来输出结果
001:当前promise的状态为pending时候,将回调函数数据保存起来!
002:如果为resolve成功,那么便调用成功的回调函数(异步任务哦,需要定时器)
003:如果是rejected状态的,失败就需要调用失败的回调函数onRejected()
注意点:that=this;是为了把指向promise的保存起来,避免this指向问题
难点: promise的结果有着以下三种情况,因此需要补货异常
01:如果抛出异常,return的promise就会失败,其reason就是error
02:如果回调函数返回的不是promise对象,那么return就是成功,其结果就是这个返回值-value
03:如果回调函数返回的是promise对象(而promise的结果在.then输出,于是需要借用.then方法),那么return的结果就是这个promise的结果(是成功就成功,是失败就失败)
使用try来补货promise的返回结果(promise对象):这就需要判断是对象还是非对象,使用到instanceof方法,
准备01
/*Promise原型对象的then()
返回一个新的promise对象,并且指定成功和失败的回调函数,
*/
Promise.prototype.then = function (onFulfilled, onRejected) { //onFulfilled形式参数,接受外面的成功的回调,然后指向resolve
const that = this;
// 01:返回一个新的promise对象
return new Promise((resolve, reject) => { //根据里面的状态执行结果,来判断是应该调用成功的回调还是失败的回调
//02:根据promise的状态来输出结果!
if (that.status === PENDING) { //假设promise的状态为pending时候,将回调函数数据保存起来!
that.callbacks.push({
onFulfilled,
onRejected
})
} else if (that.status === RESOLVED) { //如果为resolve成功,那么便调用成功的回调函数(异步任务哦,需要定时器),传入里面的value
setTimeout(() => {
/*
01:如果抛出异常,return的promise就会失败,其reason就是error
02:如果回调函数返回的不是promise对象,那么return就是成功,其结果就是这个返回值-value
03:如果回调函数返回的是promise对象(而promise的结果在.then输出,于是需要借用.then方法),
那么return的结果就是这个promise的结果(是成功就成功,是失败就失败)
*/
//注意点1:新的promise的结果,由onFulfilled或onRejected来决定的!
//注意点2:onFulfilled函数或onRejected函数执行后,根据结果来调用resolve还是reject
//注意点3:一旦调用了resolve那么返回的promise就是成功,反之亦然就是失败
//采用捕获的方式,去查看是否抛出异常
try {
const result = onFulfilled(that.data); //成功就调用onFulfilled函数( 捕获传递进来的,返回一个promise
if (result instanceof Promise) { //03:如果回调函数返回的是promise对象,那么return的结果就是这个promise的结果
//因为result这这边是promise对象,采用promise.then的方法指定成功的回调还有失败的回调!
result.then(
value => {
resolve(value); //当result成功,让return的promise也成功,这就需要调用resolve并且指定成功;
},
reason => {
reject(reason); //当result失败,让return的promise也失败,这就需要调用resolve并且指定失败;
}
)
} else { //02:如果回调函数返回的不是promise对象,那么return就是成功,其结果就是这个返回值-value
resolve(result); //值就是捕获到的结果!
}
} catch (error) {
reject(error)
}
})
} else { //rejected状态的,失败就需要调用失败的回调函数onRejected()
setTimeout(() => {
try {
const result = onRejected(that.data);
if (result instanceof Promise) {
result.then(
value => {
resolve(value); //当result成功,让return的promise也成功,这就需要调用resolve并且指定成功;
},
reason => {
reject(reason); //当result失败,让return的promise也失败,这就需要调用resolve并且指定失败;
}
)
} else { //02:如果回调函数返回的不是promise对象,那么return就是成功,其结果就是这个返回值-value
resolve(result); //值就是捕获到的结果!
}
} catch (error) {
reject(error)
}
})
}
})
}
准备01的简介版
就是在方式的1基础上,对以下这几行代码进行优化
如果回调函数返回的是promise对象(而promise的结果在.then输出,于是需要借用.then方法),那么return的结果就是这个promise的结果(是成功就成功,是失败就失败)
方式1解析:就是Promise对象的成功值为value,其结果为value,然后这个返回的promise的结果根据前面的promise(对象)结果决定的,于是就直接调用resolve并且传递了value即可!
方式2:就是既然第一个promise对象的结果作为条件给了第二个promise的结果,并且还调用了resolve的方式来传值,何不如直接把使用第一个promise调用then方法,里面传递两个回调函数,参数依旧照旧传递即可,这样去掉了外层的函数,效率也就提高了!
if (result instanceof Promise) {
// result.then(
// value => {
// resolve(value)
// },
// reason => {
// reject(reason)
// }
// )
//上面的代码简洁为下面的一行代码:
//解析:
result.then(resolve, reject);
}
准备02:在01基础上增加条件
由于捕获异常在resolve,reject,还有pending状态的时候保存数据都使用到,因此把这个封装为一个函数(handle),就是调用指定的回调函数处理,根据执行的结果,改变return的promise状态
handel的参数为传入的回调函数-callback;
调用的时候:直接使用handle(成功时候调用的是-onFulfilled),失败的时候调用时onRejected
/*Promise原型对象的then()
返回一个新的promise对象,并且指定成功和失败的回调函数,
*/
Promise.prototype.then = function (onFulfilled, onRejected) { //onFulfilled形式参数,接受外面的成功的回调,然后指向resolve
onFulfilled = typeof onFulfilled === "function" ? onFulfilled : value => value; //向后面传递value
onRejected = typeof onRejected === 'function' ? onRejected : reason => {
throw reason; //指定默认的失败回调,并且将异常穿透下去(向后面传递失败的reason)
}
const that = this;
// 01:返回一个新的promise对象
return new Promise((resolve, reject) => { //根据里面的状态执行结果,来判断是应该调用成功的回调还是失败的回调
/*
调用指定的回调函数处理,根据执行的结果,改变return的promise状态
*/
function handle(callback) { //handle---处理
/*
01:如果抛出异常,return的promise就会失败,其reason就是error
02:如果回调函数返回的不是promise对象,那么return就是成功,其结果就是这个返回值-value
03:如果回调函数返回的是promise对象(而promise的结果在.then输出,于是需要借用.then方法),
那么return的结果就是这个promise的结果(是成功就成功,是失败就失败)
*/
//注意点1:新的promise的结果,由onFulfilled或onRejected来决定的!
//注意点2:onFulfilled函数或onRejected函数执行后,根据结果来调用resolve还是reject
//注意点3:一旦调用了resolve那么返回的promise就是成功,反之亦然就是失败
//采用捕获的方式,去查看是否抛出异常
try {
const result = callback(that.data); //成功就调用onFulfilled函数( 捕获传递进来的,返回一个promise
if (result instanceof Promise) { //03:如果回调函数返回的是promise对象,那么return的结果就是这个promise的结果
//因为result这这边是promise对象,采用promise.then的方法指定成功的回调还有失败的回调!
result.then(
value => {
resolve(value); //当result成功,让return的promise也成功,这就需要调用resolve并且指定成功;
},
reason => {
reject(reason); //当result失败,让return的promise也失败,这就需要调用resolve并且指定失败;
}
)
} else { //02:如果回调函数返回的不是promise对象,那么return就是成功,其结果就是这个返回值-value
resolve(result); //值就是捕获到的结果!
}
} catch (error) {
reject(error)
}
}
//02:根据promise的状态来输出结果!
if (that.status === PENDING) { //当前promise的状态为pending时候,将回调函数数据保存起来!
that.callbacks.push({
onFulfilled(value) { //这边是在上面的callbacksObj.onFulfilled(value) 调用该函数的
handle(onFulfilled);
},
onRejected(reason) { //这边是在上面的callbacksObj.onRejected(reason) 调用该函数的
handle(onRejected);
}
})
} else if (that.status === RESOLVED) { //如果为resolve成功,那么便调用成功的回调函数(异步任务哦,需要定时器),
// 异步执行onFulfilled并且改变return的promise的状态(这是在handle封装函数内部改的)
setTimeout(() => {
handle(onFulfilled);
})
} else { //如果是rejected状态的,失败就需要调用失败的回调函数onRejected(),异步执行onRejected(),并且改变return的promise的状态
setTimeout(() => {
handle(onRejected);
})
}
})
}
(4):Promise原型对象的catch()的定义
/*Promise原型对象的catch()
指定失败的回调函数,并且返回一个新的promise对象
*/
Promise.prototype.catch = function (onRejected) {
return this.then(undefined, onRejected);
//前面undefined是为了往后面传递value,而onRejected直接异常穿透下去
//这是在上面的定义的来处理的
//onFulfilled = typeof onFulfilled === "function" ? onFulfilled : value => value; //向后面传递value
//onRejected = typeof onRejected === 'function' ? onRejected : reason => {
// throw reason; //指定默认的失败回调,并且将异常穿透下去(向后面传递失败的reason)
}
}
(5):Promise函数对象的resolve方法和reject方法的定义
/*Promise函数对象的resolve方法
返回一个指定结果成功值为value的promise
*/
Promise.resolve = function (value) {
//返回的新的promise,但是指定结果可能成功或者失败
return new Promise((resolve, reject) => {
if (value instanceof Promise) { //是promise对象,那么其value的结果作为新的promise对象的结果,
value.then(resolve, reject)
} else { //不是promise对象,状态变为resolve,那么其数据就是value
resolve(value);
}
})
}
/*Promise函数对象的reject方法
返回的是一个指定结果失败值为reason的promise
*/
Promise.reject = function (reason) {
//返回一个新的promise对象,并且指定失败的结果
return new Promise((resolve, reject) => {
reject(reason)
})
}
(6):Promise函数对象的all方法
all方法里面参数是promise对象组成的数组!
返回的是一个新的promise,只有数组中的promise都成功的时候才成功,否则有一个失败,就失败!
Promise.all = function (Promises) {
let resolveCount = 0; //定义一个计数器,用来保存promise成功的次数
const values = new Array(Promises.length); //这个数组是用来保存所有成功的promise对象组成的数组 创建数组并且指定长度
return new Promise((resolve, reject) => {
//遍历取出promised数组中的每一个promise对象
Promises.forEach((p, index) => {
//注意点:考虑到参数可能不是promise对象,隐藏把这个p外面套一个promise.resolve,反正这个返回的是一个promise结果,直接调用.then也可以
Promise.resolve(p).then(
value => {
resolveCount++; //一进入这里(代表成功),就++
//p成功了,那么将成功的value保存在values数组里面
// values.push(value);//不能直接push,因为为了使得promise对象的顺序照旧
values[index] = value; //就是遍历每一个元素,存储对应的下标进入数组values
//如果全部成功了,将return的promise改变为成功
if (resolveCount === Promises.length) {
resolve(values);
}
},
reason => { //只要有一个失败,return的promise就是失败
reject(reason)
}
)
})
})
}
(7):Promise函数对象的race方法
race方法里面参数是promise对象组成的数组!
返回的是一个promise,其结果有数组中的promise对象,结果由先最先完成的promise决定!
Promise.race = function (Promises) {
return new Promise((resolve, reject) => {
Promises.forEach((p, index) => {
Promise.resolve(p).then(
value => { //一旦成功了,那么成功的promise对象的值,就return成功,并且把成功的值为value
resolve(value);
},
reason => { //一旦失败了,那么失败的promise对象的值,就return失败,并且把失败的值为reason
reject(reason);
}
)
})
})
}
(8):在promise.js里面自定义自己的方法
01:Promise.resolveDelay 返回一个promise对象,在指定时间后才确定结果(可能成功或失败)
02:Promise.rejectDelay 返回一个promise对象,在指定时间后才确定失败
/*01:Promise.resolveDelay 返回一个promise对象,在指定时间后才确定结果(可能成功或失败) */
Promise.resolveDelay = function (value, time) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (value instanceof Promise) { //value就是这个返回的结果,可能是promise对象,可能不是
value.then(resolve, reject)
// value.then(
// value => {
// resolve(value)
// },
// reason => {
// reject(reason)
// }
// )
} else {
resolve(value)
}
})
}, time)
}
/*02:Promise.rejectDelay 返回一个promise对象,在指定时间后才确定失败 */
Promise.rejectDelay = function (reason, time) {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject(reason);
}, time)
})
}
四:手写一个promise方法的完整代码如下
/*
自定义Promise函数模块
*/
(function (window) {
const PENDING = "peding";
const RESOLVED = "resolve";
const REJECTED = "reject";
// Promise构造函数 executor:执行器函数
function Promise(executor) {
const that = this; //把that指向promise的that存再一个变量中,需要用的时候,就调用!
that.status = PENDING; //给promise对象指定status属性,初始值为pending
that.data = undefined; //给promise指定一个存储结果数据的属性
that.callbacks = []; //定义一个回调函数里面存放着可能待执行的函数,每一个元素的结构:{onFulfilled(){},onRejected(){}}
function resolve(value) {
//04:需要先判断 当前状态是否是pending,如果不是直接结束掉
if (that.status != PENDING) {
return
}
//01:将状态改为resolved
that.status = RESOLVED
//保存value数据
that.data = value;
//02:如果有待执行callback函数,立即异步执行回调函数onFulfilled()(丢到任务队列中)
if (that.callbacks.length > 0) {
setTimeout(() => { //03:放入队列中,执行所有成功的回调
that.callbacks.forEach(callbacksObj => { //遍历出回调函数数组中是否有成功的回调函数
callbacksObj.onFulfilled(value); //给成功的回调函数指定成功的结果!
});
})
}
}
function reject(reason) {
//需要先判断 当前状态是否是pending,如果不是直接结束掉
// 因为状态只能改变一次!,一进来就是reject就执行,若是pending就直接结束掉!
if (that.status != PENDING) {
return
}
that.status = REJECTED
that.data = reason;
if (that.callbacks.length > 0) {
setTimeout(() => {
that.callbacks.forEach(callbacksObj => {
callbacksObj.onRejected(reason)
})
}, 1000)
}
}
//因为使用的时候,在executor执行器函数里面传入了两个回调函数,需要在这边定义一下!
//立即同步执行exxcutor
try {
executor(resolve, reject);
} catch (error) { //然后执行器抛出异常,那么就调用reject失败函数
reject(error)
}
}
/*Promise原型对象的then()
返回一个新的promise对象,并且指定成功和失败的回调函数,
*/
Promise.prototype.then = function (onFulfilled, onRejected) { //onFulfilled形式参数,接受外面的成功的回调,然后指向resolve
onFulfilled = typeof onFulfilled === "function" ? onFulfilled : value => value; //向后面传递value
onRejected = typeof onRejected === 'function' ? onRejected : reason => {
throw reason; //指定默认的失败回调,并且将异常穿透下去(向后面传递失败的reason)
}
const that = this;
// 01:返回一个新的promise对象
return new Promise((resolve, reject) => { //根据里面的状态执行结果,来判断是应该调用成功的回调还是失败的回调
/*
调用指定的回调函数处理,根据执行的结果,改变return的promise状态
*/
function handle(callback) { //handle---处理
/*
01:如果抛出异常,return的promise就会失败,其reason就是error
02:如果回调函数返回的不是promise对象,那么return就是成功,其结果就是这个返回值-value
03:如果回调函数返回的是promise对象(而promise的结果在.then输出,于是需要借用.then方法),
那么return的结果就是这个promise的结果(是成功就成功,是失败就失败)
*/
//注意点1:新的promise的结果,由onFulfilled或onRejected来决定的!
//注意点2:onFulfilled函数或onRejected函数执行后,根据结果来调用resolve还是reject
//注意点3:一旦调用了resolve那么返回的promise就是成功,反之亦然就是失败
//采用捕获的方式,去查看是否抛出异常
try {
const result = callback(that.data); //成功就调用onFulfilled函数( 捕获传递进来的,返回一个promise
if (result instanceof Promise) { //03:如果回调函数返回的是promise对象,那么return的结果就是这个promise的结果
//因为result这这边是promise对象,采用promise.then的方法指定成功的回调还有失败的回调!
result.then(
value => {
resolve(value); //当result成功,让return的promise也成功,这就需要调用resolve并且指定成功;
},
reason => {
reject(reason); //当result失败,让return的promise也失败,这就需要调用resolve并且指定失败;
}
)
} else { //02:如果回调函数返回的不是promise对象,那么return就是成功,其结果就是这个返回值-value
resolve(result); //值就是捕获到的结果!
}
} catch (error) {
reject(error)
}
}
//02:根据promise的状态来输出结果!
if (that.status === PENDING) { //当前promise的状态为pending时候,将回调函数数据保存起来!
that.callbacks.push({
onFulfilled(value) { //这边是在上面的callbacksObj.onFulfilled(value) 调用该函数的
handle(onFulfilled);
},
onRejected(reason) { //这边是在上面的callbacksObj.onRejected(reason) 调用该函数的
handle(onRejected);
}
})
} else if (that.status === RESOLVED) { //如果为resolve成功,那么便调用成功的回调函数(异步任务哦,需要定时器),
// 异步执行onFulfilled并且改变return的promise的状态(这是在handle封装函数内部改的)
setTimeout(() => {
handle(onFulfilled);
})
} else { //如果是rejected状态的,失败就需要调用失败的回调函数onRejected(),异步执行onRejected(),并且改变return的promise的状态
setTimeout(() => {
handle(onRejected);
})
}
})
}
/*Promise原型对象的catch()
指定失败的回调函数,并且返回一个新的promise对象
*/
Promise.prototype.catch = function (onRejected) {
return this.then(undefined, onRejected);
//前面undefined是为了往后面传递value,而onRejected直接异常穿透下去
}
/*Promise函数对象的resolve方法
返回一个指定结果成功值为value的promise
*/
Promise.resolve = function (value) {
//返回的新的promise,但是指定结果可能成功或者失败
return new Promise((resolve, reject) => {
if (value instanceof Promise) { //是promise对象,那么其value的结果作为新的promise对象的结果,
value.then(resolve, reject)
} else { //不是promise对象,状态变为resolve,那么其数据就是value
resolve(value);
}
})
}
/*Promise函数对象的reject方法
返回的是一个指定结果失败值为reason的promise
*/
Promise.reject = function (reason) {
//返回一个新的promise对象,并且指定失败的结果
return new Promise((resolve, reject) => {
reject(reason)
})
}
/*Promise函数对象的all方法 all方法里面参数是promise对象组成的数组!
返回的是一个promise,只有数组中的promise都成功的时候才成功,否则有一个失败,就失败!
*/
Promise.all = function (Promises) {
let resolveCount = 0; //定义一个计数器,用来保存promise成功的次数
const values = new Array(Promises.length); //这个数组是用来保存所有成功的promise对象组成的数组 创建数组并且指定长度
return new Promise((resolve, reject) => {
//遍历取出promised数组中的每一个promise对象
Promises.forEach((p, index) => {
//注意点:考虑到参数可能不是promise对象,隐藏把这个p外面套一个promise.resolve,反正这个返回的是一个promise结果,直接调用.then也可以
Promise.resolve(p).then(
value => {
resolveCount++; //一进入这里(代表成功),就++
//p成功了,那么将成功的value保存在values数组里面
// values.push(value);//不能直接push,因为为了使得promise对象的顺序照旧
values[index] = value; //就是遍历每一个元素,存储对应的下标进入数组values
//如果全部成功了,将return的promise改变为成功
if (resolveCount === Promises.length) {
resolve(values);
}
},
reason => { //只要有一个失败,return的promise就是失败
reject(reason)
}
)
})
})
}
/*Promise函数对象的race方法 race方法里面参数是promise对象组成的数组!
返回的是一个promise,其结果有数组中的promise对象,先完成的promise决定!
*/
Promise.race = function (Promises) {
return new Promise((resolve, reject) => {
Promises.forEach((p, index) => {
Promise.resolve(p).then(
value => { //一旦成功了,那么成功的promise对象的值,就return成功,并且把成功的值为value
resolve(value);
},
reason => { //一旦失败了,那么失败的promise对象的值,就return失败,并且把失败的值为reason
reject(reason);
}
)
})
})
}
/*
在promise.js里面自定义自己的方法:
*/
/*01:Promise.resolveDelay 返回一个promise对象,在指定时间后才确定结果(可能成功或失败) */
Promise.resolveDelay = function (value, time) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (value instanceof Promise) { //value就是这个返回的结果,可能是promise对象,可能不是
value.then(resolve, reject)
// value.then(
// value => {
// resolve(value)
// },
// reason => {
// reject(reason)
// }
// )
} else {
resolve(value)
}
})
}, time)
}
/*02:Promise.rejectDelay 返回一个promise对象,在指定时间后才确定失败 */
Promise.rejectDelay = function (reason, time) {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject(reason);
}, time)
})
}
//向外暴露Promise函数
window.Promise = Promise
})(window)
/*
在promise方法里面自定义自己的方法:
*/