Promise.reject().then((val)=>{
return ‘ok’
},()=>{
return ‘err’
}).then((val)=>{
console.log(‘ok’ + val)
},(e)=>{
console.log(‘err’ + e)
})
// okerr 第一个then失败的回调返回的是普通值,还是走第二个的then中成功回调
2.如果成功或者失败的回调的返回值 返回是一个promise 那么会让这个promise执行 采用他的状态
Promise.resolve().then(()=>{
return new Promise((resolve)=>{
setTimeout(()=>{
resolve(1)
},1000)
})
}).then((val)=>{
console.log(val)
})
//一秒后打印1
3.2实现
这一版主要是实现链式调用,稍微绕一点,但是理清楚了也不难
首先明确一下,then后面会返回一个新的Promise,所以才能执行链式调用
第一个比较绕的地方,怎么让第二个then里面的回调执行?只要调用then返回的新promise(promise2)时的resolve方法就行了
第二个比较绕的地方就是参数是什么?我们看特性3.1,参数是什么要根据第一个then中回调的返回值来判断,返回值如果是正常值,如果是Piomise,,所以我们封装一个resolvePromise的方法来处理,参数的话有第一个then的回调,新创建的promise2,以及promise2里面的resolve.reject
需要改变的核心代码如下
let resolvePromise = (promise2, x, resolve, reject) => {…}
class Promise {
construcotr(){…}
then(){
let promise2 = new promise((resolve,reject)=>{
let x = onFulfiled() // onFulfilef是第一个then中的回调函数
resolvePromise(promise2,x, resolve, reject)
})
return promiese2
}
}
resolvePromise这个方法会判断onFulfiled返回值类型,如果是普通值会怎么样,如果是一个Promise会怎么样,如果报错会怎么样,详细实现方法可以参考promise A+规范
完整实现
let resolvePromise = (promise2, x, resolve, reject) => {
// 监测到环形链
if(promise2===x) return new TypeError(‘chaining cycle detected for promise’)
if(typeof x ===‘function’ ||(typeof x ===‘object’ && x!==null)){
try{
//尝试取出then,有问题报错
let then = x.then
if(typeof then === ‘function’){ //这里是最绕的,想清楚promise2和x的关系,x.then会不会执行取决于使用者的逻辑,会不会在第一个then中回调函数中返回的promise中调用它的resolve改变状态
then.call(x,resolve,reject)
}else{// then不是function
resolve(x)
}
}catch (e) {
reject(e)
}
}else{ //普通类型
resolve(x)
}
}
class Promise {
constructor(executor) {
this.status = ‘pending’
this.value = undefined
this.reason = undefined
this.onFulfilledCallback = []
this.onRejectedCallback = []
let resolve = (value) => {
if (this.status === ‘pending’) {
this.status = ‘fulfilled’
this.value = value
this.onFulfilledCallback.forEach(fn => fn(this.value))
}
}
let reject = (reason) => {
if (this.status === ‘pending’) {
this.status = ‘rejected’
this.reason = reason
this.onRejectedCallback.forEach(fn => fn(this.reason))
}
}
try {
executor(resolve, reject)
} catch (e) {
reject(e)
}
}
then(onFulfilled, onRejected) { // 如果then的时候 根据当前状态执行成功或者失败
let promise2 = new Promise((resolve, reject) => {
if (this.status === ‘fulfilled’) {
setTimeout(() => { //这里之所以异步是因为必须保证resolvePromise(promise2, x, resolve, reject)时Promise2创建完成
try {
let x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
}
if (this.status === ‘rejected’) {
setTimeout(() => {
try {
let x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
}
if (this.status === ‘pending’) {
this.onFulfilledCallback.push(() => {
setTimeout(() => {
try {
let x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
})
this.onRejectedCallback.push(() => {
setTimeout(() => {
try {
let x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
})
}
})
return promise2
}
}
基本面试5-10分钟代码写到这里,都能给满分通过,剩下的就是4个打补丁的地方了
4.打补丁
4.1 补丁点
实际上是A+规范测试用例的补丁,我按重要程度往下排,前面的必须做到能写出来(面试可以不写),后面的知道即可
- then的默认参数配置
- x可能是个Promise,它的返回值还可能是个Pormise,这个Promised的返回值还可能是个Promise…
- 调用Promise的resolve方法,如果参数是个promise怎么办 (这个不在A+规范里,但是新版promise实现了)
- 别人实现的可能不规范,我们的resolvePromise需要加一点限制,改变了状态就不能再变了 (这个在A+规范测试用例里,但是我感觉意义不大)
4.1.1 默认参数
Promise.resolve(1).then().then().then().then((val)=>{
console.log(val) //1
})
//失败也是类似的传递
可以默认传递一个回调函数
then(onFufilled,onRejected){
onFufilled = typeof onFufilled === ‘function’?onFufilled:value=>value;
…
}
4.1.2 x中promise嵌套
这个也不难,递归调用resolvePromise去解析
let resolvePromise = (promise2,x,resolve,reject) => {
…
then = x.then
/*这个是之前的核心代码 then.call(x,resolve,reject)
*实际等同于 then.call(x,(y)=>{
-
resolve(y) 这个y是x作为promise的返回值,现在这个y可能是个promise所以再递归调用resolvePromise去解析
-
},reject)
*/
改成这样:
then.call(x,(y)=>{
resolvePromise((promise2,y,resolve,reject)
},reject)
…
}
4.1.3 resolve中是promise
constructor(executor){
…
let resolve = (value) =>{ // 如果resolve的值时一个promise
if(value instanceof Promise){
// 我就让这个promise执行,把成功的结果再次判断
return value.then(resolve,reject) //参数会自动传递到resolve里面去
}
}
…
5.添加方法
Promise比较重要的方法一共有五个方法
5.1 Promise.resovle
把一个对象包装成Promise对象,特别注意状态不一定是成功的
各种注意事项请看阮一峰es6-promise
直接记忆不好记忆,但是结合源码很简单,理所当然
static resolve(value){
return new Promise((resolve,reject)=>{
resolve(value);
})
}
5.2 Promise.reject
Promise.reject(reason)
方法也会返回一个新的 Promise 实例,该实例的状态为rejected
。
static reject(err){
return new Promise((resolve,reject)=>{
reject(err);
})
}
5.3 PromiseInstance.prototype.finally
这个是实例方法,其他几个都是类方法
无论成功还是失败都会调用,所以可定返回的也是一个Promimse,成功失败都会调用传入的回调,
finally不接受值,返回的Promise的状态受前一个promise状态的影响
finally如果在中间同时回调返回一个promise则会等待promise
Promise.resolve(1).finally(
(a)=>{
return new Promise((resolve)=>{
setTimeout(function () {
resolve(2)
},3000)
})
}
).then((data)=>{
console.log(data)
})
等待3秒后打印1
finally实现
Promise.prototype.finally = function (callback) {
let P = this.constructor;
return this.then(
value => P.resolve(callback()).then(() => value),
reason => P.resolve(callback()).then(() => { throw reason })
);
};
5.4 Promise.race Promise.all
race和all一个是谁先调用谁执行后面then中的回调,一个是全部调用才执行后面then中的回调
他们都需要对参数中传入的数组进行遍历
all的实现需要借助计数器,这也是实现异步任务通知的一种方法
直接完成或者异步完成都会使计数器加1 当计数器和数组长度相等时就是all方法完成的时候
,然后把结果数组传到下一个回调
race的实现就是,遍历数组中元素current,都去改变返回promise的值,谁先改变就取谁的值传到会带到函数里面
return promose((resolve,reject)=>{
if(isPromise(current)){
current.then(resolve,reject)
}else{
resolve(current)
}
})
具体实现见6
6.完整实现
let resolvePromise = (promise2,x,resolve,reject) => {
if(promise2 === x){
return reject(new TypeError(‘Chaining cycle detected for promise #’))
}
// 如果调用了失败 就不能再调用成功 调用成功也不能再调用失败
let called;
if(typeof x =‘function’ || (typeof x === ‘object’ && x! null) ){
try{
let then = x.then; // Object,dedefineProperty
if(typeof then === ‘function’){
then.call(x,(y)=>{ // x.then(y=>,err=>)
if(called) return;
called = true
// y有可能解析出来的还是一个promise
// 在去调用resolvePromise方法 递归解析的过程
// resolve(y)
resolvePromise(promise2,y,resolve,reject); // 总有y是普通值的时候
},e=>{
if(called) return;
called = true
reject(e);
})
}else{
if(called) return;
called = true
resolve(x);
}
}catch(e){
if(called) return;
called = true
reject(e);
}
}else{
if(called) return;
called = true
resolve(x); // ‘123’ 123
}
}
class Promise{
constructor(executor){
this.value = undefined;
this.reason = undefined;
this.status = ‘pending’;
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
let resolve = (value) =>{ // 如果resolve的值时一个promise
// if(typeof value === ‘function’ || (typeof value == ‘object’&&value !== null)){
// if(typeof value.then == ‘function’){
// return value.then(resolve,reject)
// }
// }
if(value instanceof Promise){
// 我就让这个promise执行,把成功的结果再次判断
return value.then(resolve,reject) //参数会自动传递到resolve里面去
}
if(this.status === ‘pending’){
this.status = ‘fulfilled’
this.value = value;
this.onResolvedCallbacks.forEach(fn=>fn());
}
}
let reject = (reason) =>{
if(this.status === ‘pending’){
this.status = ‘rejected’
this.reason = reason;
this.onRejectedCallbacks.forEach(fn=>fn());
}
}
try{
executor(resolve,reject);
}catch(e){
console.log(e)
reject(e);
}
}
then(onFufilled,onRejected){
// 可选参数的配置
onFufilled = typeof onFufilled === ‘function’?onFufilled:value=>value;
onRejected = typeof onRejected === ‘function’?onRejected:err=>{throw err}
let promise2 = new Promise((resolve,reject)=>{
if(this.status === ‘fulfilled’){
setTimeout(()=>{ // 为了保证promise2 已经产生了
try{
let x = onFufilled(this.value);
resolvePromise(promise2,x,resolve,reject);
}catch(e){
console.log(e);
reject(e);
}
})
}
if(this.status === ‘rejected’){
setTimeout(() => {
try{
let x= onRejected(this.reason);
resolvePromise(promise2,x,resolve,reject);
}catch(e){
reject(e);
}
});
}
if(this.status === ‘pending’){
this.onResolvedCallbacks.push(()=>{
setTimeout(() => {
try{
let x = onFufilled(this.value);
resolvePromise(promise2,x,resolve,reject);
}catch(e){
reject(e);
}
})
});
this.onRejectedCallbacks.push(()=>{
setTimeout(() => {
try{
let x= onRejected(this.reason);
resolvePromise(promise2,x,resolve,reject);
}catch(e){
reject(e);
}
});
});
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)
结尾
学习html5、css、javascript这些基础知识,学习的渠道很多,就不多说了,例如,一些其他的优秀博客。但是本人觉得看书也很必要,可以节省很多时间,常见的javascript的书,例如:javascript的高级程序设计,是每位前端工程师必不可少的一本书,边看边用,了解js的一些基本知识,基本上很全面了,如果有时间可以读一些,js性能相关的书籍,以及设计者模式,在实践中都会用的到。
[外链图片转存中…(img-24OPaqMM-1713635914824)]
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)
[外链图片转存中…(img-heJ0gbfY-1713635914824)]
结尾
学习html5、css、javascript这些基础知识,学习的渠道很多,就不多说了,例如,一些其他的优秀博客。但是本人觉得看书也很必要,可以节省很多时间,常见的javascript的书,例如:javascript的高级程序设计,是每位前端工程师必不可少的一本书,边看边用,了解js的一些基本知识,基本上很全面了,如果有时间可以读一些,js性能相关的书籍,以及设计者模式,在实践中都会用的到。