尚硅谷2023版Promise教程从入门到实战(讲师:任安萍)
一、前言:为什么会出现Promise?
Promise的重要性我认为没有必要多讲,概括起来说就是五个字:必!须!得!掌!握!。
而且还要掌握透彻,在实际的使用中,有非常多的应用场景我们不能立即知道应该如何继续往下执行。
最常见的一个场景就是ajax请求,通俗来说,由于网速的不同,可能你得到返回值的时间也是不同的,
这个时候我们就需要等待,结果出来了之后才知道怎么样继续下去。
let xhr = new XMLHttpRequest();
xhr.open('get', 'https://v0.yiketianqi.com/api?unescape=1&version=v61&appid=82294778&appsecret=4PKVFula&city=%E5%8C%97%E4%BA%AC');
xhr.send();
xhr.onreadystatechange = function () {if (xhr.readyState === 4) {if (xhr.status >= 200 && xhr.status < 300) {console.log(xhr.responseText)}}
}
在ajax的原生实现中,利用了onreadystatechange事件,当该事件触发并且符合一定条件时,才能拿到想要的数
据,之后才能开始处理数据,这样做看上去并没有什么麻烦,但如果这个时候,我们还需要另外一个ajax请求,这
个新ajax请求的其中一个参数,得从上一个ajax请求中获取,这个时候我们就不得不等待上一个接口请求完成之
后,再请求后一个接口。
let xhr = new XMLHttpRequest();
xhr.open('get', 'https://v0.yiketianqi.com/api?unescape=1&version=v61&appid=82294778&appsecret=4PKVFula&city=%E5%8C%97%E4%BA%AC');
xhr.send();
xhr.onreadystatechange = function () {if (xhr.readyState === 4) {if (xhr.status >= 200 && xhr.status < 300) {console.log(xhr.responseText)//伪代码....let xhr = new XMLHttpRequest();xhr.open('get','http://www.xx.com?a'+xhr.responseText);xhr.send();xhr.onreadystatechange = function(){if(xhr.readyState === 4){if(xhr.status>=200 && xhr.status<300){console.log(xhr.responseText)}}}}}
}
当出现第三个ajax(甚至更多)仍然依赖上一个请求时,我们的代码就变成了一场灾难。
这场灾难,往往也被称为回调地狱。
因此我们需要一个叫做Promise的东西,来解决这个问题,当然,除了回调地狱之外,还有个非常重要的需求就是
为了代码更加具有可读性和可维护性,我们需要将数据请求与数据处理明确的区分开来。
上面的写法,是完全没有区分开,当数据变得复杂时,也许我们自己都无法轻松维护自己的代码了。
这也是模块化过程中,必须要掌握的一个重要技能,请一定重视。
二、Promise是什么?
Promise是异步编程的一种解决方案,比传统的解决方案回调函数更合理、更强大。
ES6将其写进了语言标准,统一了用法,原生提供了Promise对象。
指定回调函数的方式也变得更加灵活易懂,也解决了异步
回调地狱
的问题旧方案是单纯使用回调函数,常见的异步操作有:定时器、fs模块、ajax、数据库操作
从语法上说,Promise是一个构造函数;
从功能上说,Promise对象用来封装一个异步操作并可以获取其成功/失败的结果值。
2.1 Promise的初体验
创建promise对象(pending状态)
const p = new Promise(executor);
其中:
executor函数: 执行器 (resolve, reject) => {}
resolve函数: 内部定义成功时我们调用的函数 value => {}
reject函数: 内部定义失败时我们调用的函数 reason => {}
executor会在Promise内部立即同步调用,异步操作在执行器中执行
实例对象调用Promise原型中的then方法来完成对结果的处理
<script>const p = new Promise((resolve, reject) => {//如果咱们公司今年挣钱了,年底就发奖金,否则不发resolve('ok');})console.log(p)p.then(() => {console.log('发奖金')}, () => {console.log('不发奖金')})
</script>
三、使用Promise的好处?
3.1 指定回调函数的方式更加灵活
-
旧的:必须在启动异步任务前指定
-
promise:启动异步任务->返回promise对象->给promise对象绑定回调函数
(甚至可以在异步任务结束后指定/多个)
3.2 可以解决回调地狱问题,支持链式调用
-
什么是回调地狱?
回调函数嵌套调用,外部回调函数异步执行的结果是嵌套的回调执行的条件
-
回调地狱的缺点?
不便于阅读
不便于异常处理
-
解决方案?
promise链式调用
-
终极解决方案?
async/await
四、Promise实例对象的两个属性
-
PromiseState
此属性为promise对象的状态属性。
- fulfilled:成功的状态
- rejected:失败的状态
- pending:初始化的状态
【注】状态只能由pending->fulfilled 或者是 pending->rejected
-
PromiseResult
此属性为promise对象的结果值(resolve以及reject函数的形参值)
五、resolve函数以及reject函数
- resolve:修改promise对象的状态,由pending修改到fulfilled;将实参设置到这个属性PromiseResult中。
- reject:修改promise对象的状态,由pending修改到rejected;将实参设置到这个属性PromiseResult中。
案例1:利用promise来进行读取文件操作
//1.普通文件读取方式
const fs = require('fs');//2.直接利用readfile来进行读取
/* fs.readFile(__dirname + '/data.txt',(err,data)=>{if(err) throw err;console.log(data.toString());
}) *///3.利用promise来实现文件的读取
const p = new Promise((resolve, reject) => {fs.readFile(__dirname + '/data.txt', (err, data) => {if (err) {reject(err);}else{resolve(data);}})
}); p.then(value=>{console.log(value.toString());
},reason=>{console.log(reason);
})
案例2:利用promise进行ajax请求
<body><button>发送ajax请求</button><script>//1.获取DOM元素对象let btn = document.querySelector('button');//2.绑定事件btn.onclick = function(){//3.创建promise实例对象const p = new Promise((resolve,reject)=>{//4.创建ajax实例对象const xhr = new XMLHttpRequest();//5.打开请求xhr.open('get','https://www.yiketianqi.com/free/day?appid=82294778&appsecret=4PKVFula&unescape=1');//6.发送请求xhr.send();//7.利用onreadystatechange事件xhr.onreadystatechange = function(){//8.判断if(xhr.readyState == 4){if(xhr.status == 200){resolve(xhr.responseText);}else{reject(xhr.response);}}}});p.then(value=>{console.log(JSON.parse(value));},reason=>{console.log('获取信息失败');})}</script>
</body>
案例3:利用promise进行数据库操作
const mongoose = require('mongoose');new Promise((resolve, reject) => {mongoose.connect('mongodb://127.0.0.1/project');mongoose.connection.on('open', ()=>{//连接成功的情况resolve();});mongoose.connection.on('error', () => {//连接失败的情况reject();})
}).then(value => {//创建结构const NoteSchema = new mongoose.Schema({title: String,content: String})//创建模型const NoteModel = mongoose.model('notes', NoteSchema);//读取操作NoteModel.find().then(value => {console.log(value);}, reason => {console.log(reason);})
}, reason => {console.log('连接失败');
})
案例4:封装一个函数,作用是读取文件
const fs = require('fs');function ReadFileFun(path){return new Promise((resolve,reject)=>{fs.readFile(path,(err,data)=>{//判断if(err){reject(err)}else{resolve(data);}})});
}ReadFileFun('./data.txt').then(value=>{console.log(value.toString());
},reason=>{console.log(reason);
})
node中的promisify
- promisify (只能在 NodeJS 环境中使用)
- promisify 是 util 模块中的一个方法 util 是 nodeJS 的内置模块
- 作用: 返回一个新的函数, 函数的是 promise 风格的.
const util = require('util');
const fs = require('fs');
//通过 fs.readFile 创建一个新的函数
const mineReadFile = util.promisify(fs.readFile);mineReadFile('./resource/2.html')
.then(value => {console.log(value.toString());
}, reason => {console.log(reason);
})
六、Promise对象的状态
Promise对象通过自身的状态来控制异步操作,Promise实例具有三种状态.
- 异步操作未完成:pending
- 异步操作成功:fulfilled
- 异步操作失败:rejected
这三种的状态的变化途径只有两种
- 从pending(未完成)到fulfilled(成功)
- 从pending(未成功)到rejected(失败)
一旦状态发生变化,就凝固了,不会再有新的状态变化,这也是Promise这个名字的由来,它的英语意思"承诺",
一旦承诺生效,就不得再改变了,这也意味着Promise实例的状态变化只可能发生一次。
在Promise对象的构造函数中,将一个函数作为第一个参数。而这个函数,就是用来处理Promise的状态变化。
上面的resolve和reject都为一个函数,他们的作用分别是将状态修改为resolved和rejected。
因此,Promise的最终结果只有两种。
异步操作成功,Promise实例传回一个值(value),状态变为fulfilled.
异步操作失败,Promise实例抛出一个错误(error),状态变为rejected
七、Promise的then方法
then:指定用于得到成功value的成功回调和用于得到失败reason的失败回调,返回一个新的promise对象
- 成功的状态:执行第一个回调函数
- 失败的状态:执行第二个回调函数
promise.then()返回的新promise的结果状态由什么决定?
(1) 简单表达: 由then()指定的回调函数执行的结果决定
(2) 详细表达:
① 如果抛出异常, 新promise变为rejected, reason为抛出的异常
const p = new Promise((resolve,reject)=>{resolve('ok');
});let result = p.then(value=>{throw '错误';
},reason=>{console.log(reason);
});console.log(result);
② 如果返回的是非promise的任意值, 新promise变为fulfilled, PromiseResult为返回的值
const p = new Promise((resolve,reject)=>{resolve('ok');
});let result = p.then(value=>{return 100;
},reason=>{console.log(reason);
});console.log(result);
③ 如果返回的是另一个新promise, 此promise的结果就会成为新promise的结果
const p = new Promise((resolve,reject)=>{resolve('ok');
});let result = p.then(value=>{return new Promise((resolve,reject)=>{//resolve('111');reject('error');})
},reason=>{console.log(reason);
});console.log(result);
八、Promise的链式调用
const p = new Promise((resolve,reject)=>{//resolve('ok');reject('error');
});p.then(value=>{console.log(value);
},reason=>{console.log(reason);
}).then(value=>{console.log(value);
},reason=>{console.log(reason);
})
案例:通过promise的链式调用来读取文件
回调地狱的方式:
const fs = require('fs');
fs.readFile('./resource/1.html',(err,data1)=>{if(err) throw err;fs.readFile('./resource/1.html',(err,data2)=>{if(err) throw err;fs.readFile('./resource/1.html',(err,data3)=>{if(err) throw err;console.log(data1 + data2 + data3);})})
})
Promise的形式:
需求:读取resource下三个文件内容,并在控制台合并输出
new Promise((resolve,reject)=>{fs.readFile('./resource/1.html',(err,data)=>{//如果失败 则修改promise对象状态为失败if(err) reject(err);//如果成功 则修改promise对象状态为成功resolve(data);})
}).then(value=>{return new Promise((resolve,reject)=>{fs.readFile('./resource/2.html',(err,data)=>{//失败if(err) reject(err);//成功resolve([value,data]);})})
}).then(value=>{return new Promise((resolve,reject)=>{fs.readFile('./resource/3.html',(err,data)=>{//失败if(err) reject(err);value.push(data);//成功resolve(value);})})
}).then(value=>{console.log(value.join(""));
})
九、Promise下的几种方法
9.1 Promise.resolve()
将一个普通值转化为promise类型的数据
- 若参数为非promise对象,则返回的结果为成功状态的promise对象
let p1 = Promise.resolve(123);
console.log(p1);
let p2 = Promise.resolve(undefined);
console.log(p2);
- 若参数为promise对象,参数的状态决定返回结果的状态
let p3 = Promise.resolve(new Promise((resolve,reject)=>{resolve('success');
}));
console.log(p3);let p4 = Promise.resolve(Promise.resolve(Promise.resolve("OK")));
console.log(p4);
9.2 Promise.reject()
返回的结果始终为失败的Promise对象
console.log(Promise.reject(123));
console.log(Promise.reject(Promise.resolve('ok')));
9.3 Promise.catch()
功能是用来指定失败的回调函数
let p = new Promise((resolve,reject)=>{//resolve('success');reject('error');
});p.catch(reason=>{console.log(reason);
});//then方法中不是必须传入两个参数,可以只传递成功时的回调函数
//也可以单独使用catch来指定失败的回调函数//异常(错误)穿透
//当如果有多个需要执行的成功时的回调函数,可以不需要每一次都写失败回调,可以统一最后利用catch
//当如果promise对象的状态为reject的话,会一直向下穿透直到catch方法
p.then(value=>{console.log(value);
}).then(value=>{console.log(value);
}).catch(reason=>{console.log(reason);
})
9.4 Promise.all()
作用:针对于多个Promise的异步任务进行处理
接收的参数:promise数组
返回值:promise对象,状态由promise数组中的对象状态
决定
- 若每个对象状态
都为
成功,则返回的promise对象状态为成功,
成功的结果值为每个promise对象成功结构值组成的数组
- 若
其中一个对象
状态为失败,则返回的promise对象状态为失败,
失败的结果值为失败的promise对象的结果值
let p1 = new Promise((resolve, reject) => {resolve('ok');
})
let p2 = Promise.resolve('hello');
let p3 = Promise.resolve('oh yeah');
let result = Promise.all([p1, p2, p3])
console.log(result);
当有一个ajax请求,它的参数需要另外2个甚至更多请求都有返回结果之后才能确定,
那么这个时候,就需要用到Promise.all来帮助我们应对这个场景。
Promise.all接收一个Promise对象组成的数组作为参数,
当这个数组所有的Promise对象状态都变成resolved或者rejected的时候,它才会去调用then方法。
//ES6中对Promise.all()的理解以及应用场景
//用于将多个Promise实例,包装成一个新的Promise实例
let p1 = new Promise((resolve,reject)=>{resolve('成功01');
})
let p2 = new Promise((resolve,reject)=>{resolve('成功02');
}).catch(reason=>console.log(reason));
let p3 = new Promise((resolve,reject)=>{resolve('成功03');
})
//参数可以不是数组,但必须是iterator接口
let pAll = Promise.all([p1,p2,p3]);
console.log(pAll)
//pAll的状态是由p1,p2,p3来决定,只有当这三个都为成功,pAll才会为成功,反之,但凡其中一个失败结果就是失败
//这个时候第一个失败的实力的返回值会传递给pAll的回调函数,如果作为参数的实例,自己定义了catch方法,那么它一旦为rejected,是不会触碰到pAll中的catch方法
pAll.then(value=>{console.log(value);
},reason=>{console.log(reason);
})
案例1:模拟请求三个接口中的数据,全部请求成功后获取。
function getUsersList() {return new Promise((resolve, reject) => {//模拟请求用户列表数据setTimeout(() => {resolve('用户列表的数据');}, 1000);})
}
function getBannersList() {return new Promise((resolve, reject) => {//模拟请求用户列表数据setTimeout(() => {resolve('轮播图的数据');}, 2000);})
}
function getVideoList() {return new Promise((resolve, reject) => {//模拟请求用户列表数据setTimeout(() => {resolve('视频列表的数据');}, 3000);})
}
//初始加载的时候
function initLoad() {let all = Promise.all([getUsersList(), getBannersList(), getVideoList()]);//获取成功请求的结果值all.then(value => {console.log(value);})
}
initLoad();
案例2:修改多文件读取代码
const fs = require('fs');
const util = require('util');
const mywriteFile = util.promisify(fs.readFile);
let one = mywriteFile('./resource/1.html');
let two = mywriteFile('./resource/2.html');
let three = mywriteFile('./resource/3.html');
let result = Promise.all([one,two,three]);
result.then(value=>{console.log(value.join(''));
},reason=>{console.log(reason);
})
9.5 Promise.race()
Promise.race race 赛跑的意思
参数: promise 数组
返回结果: promise 对象
状态由『最先改变状态的 promise对象』决定
结果值由 『最先改变状态的 promise对象』决定
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);
与Promise.all相似的是,Promise.race都是以一个Promise对象组成的数组作为参数。
不同的是,只要当数组中的其中一个Promsie状态变成resolved或者rejected时,就可以调用.then方法了。
而传递给then方法的值也会有所不同。
<script>//ES6中Promise.race的用法以及使用场景//将多个Promise实例包装成一个新的Promise实例let p1 = new Promise((resolve, rejct) => {setTimeout(() => {resolve('p1成功')}, 2000);})let p2 = new Promise((resolve, rejct) => {setTimeout(() => {resolve('p2成功');}, 1000);}, 1000);//调用const prace = Promise.race([p1, p2]);//Promise.race区别于Promise.all://只要是实例中有一个先改变状态,就会把这个实例的返回值传递给prace的回调函数
</script>
//使用场景:请求超时提示
function request() {return new Promise((resolve, reject) => {setTimeout(() => {resolve('请求成功');}, 4000);})
}
function timeout() {return new Promise((resolve, reject) => {setTimeout(() => {reject('网络不畅,请求超时');}, 3000);});
}
Promise.race([request(), timeout()]).then(value => {console.log(value)
}).catch(reason => {console.log(reason)
})
9.6 Promise.allSettled()
Promise.allSettled()方法,用来确定要一组异步操作是否都结束了(不管成功或失败)。
所以,它的名字叫"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>
9.7 Promise.any()
只要参数实例有一个变成fulfilled状态,包装实例就会变成fulfiilled状态;
如果所有参数实例都变成rejected,包装实例就会变成rejected状态。
Promise.any()跟Promise.race()方法很像,但是有一点不同,
就是Promise.any()不会因为某个Promise变成rejected状态而结束,
必须等到所有参数Promise变成rejected状态才会结束。
<script>let p1 = new Promise((resolve, reject) => {setTimeout(() => {resolve('ok');}, 1000)})let p2 = new Promise((resolve, reject) => {setTimeout(() => {resolve('okk');}, 2000)})let p3 = new Promise((resolve, reject) => {setTimeout(() => {reject('error');}, 3000)})Promise.any([p1, p2, p3]).then(res => {console.log(res)}).catch(err => {console.log('error')})
</script>
9.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')
})
十、终止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);
});
十一、几个关键问题
11.1 如何修改 promise 对象状态
<script>//如何修改 promise 对象状态let p = new Promise((resolve, reject) => {//1. resolve// resolve('success');//2. reject// reject('error');//3. 抛出错误 异常// throw '出问题啦! 你说出这样的话 你没有良心!!';// 状态的改变只有一次 resolve('ok');reject('error');});console.log(p);
</script>
11.2 指定多个回调执行情况
问题:一个promise指定多个成功/失败回调函数,都会调用吗?
答:会,但是前提是当promise对象的状态改变(fulfilled/rejected)时才会调用
<script>let p = new Promise((resolve, reject) => {//promise对象是可以多次调用then方法完成多个成功/失败回调函数//但是使用的前提是这个promise对象的状态必须要么是fulfilled或者是rejected//不能是pendingresolve('OK');}); //第一次指定回调p.then(value => {console.log(value);}, reason => {console.error(reason);});p.then(value => {alert(value);}, reason => {alert(reason);})
</script>
11.3 指定回调与改变状态先后顺序问题
改变promise状态和指定回调函数执行谁先谁后?
-
都有可能,正常情况下是先指定回调再改变状态,但也可以先改变状态在指定回调
//若执行器函数中是异步任务, 则先指定回调, 然后再改变状态 更为常见 //若执行器函数中是同步任务, 则先改变状态, 然后再指定回调 let p = new Promise((resolve, reject) => {//同步任务//resolve('ok');//异步任务setTimeout(() => {resolve('ok');}, 1000); });
-
如何先改状态再指定回调?
- 在执行器中直接调用resolve()/reject()
let p = new Promise((resolve, reject) => {//resolve('ok');reject('error'); });
- 延迟更长时间才调用then()
const p = new Promise((resolve, reject) => {setTimeout(() => {resolve('ok');}, 1000)}) //then方法使用定时器延迟更久的时间 setTimeout(() => {p.then(value => {console.log(value);}, reason => {console.log(reason);})}, 3000)
-
什么时候才能得到数据?
- 如果是先指定的回调,那当状态发生改变时,回调函数就会调用,得到数据
- 如果先改变的状态,那当指定回调时,回调函数就会调用,得到数据
11.4 promise.then()返回的新promise的结果状态由什么决定?
- 简单表达:由then指定的回调函数执行的结果决定
- 详细表达:
- 如果抛出异常:新promise对象状态变成rejected,reason为抛出的异常
- 如果返回的是是非promise的任意值,新promise对象状态变成fulfilled,value为返回的值
- 如果返回的是另一个新的promise对象,此promise的结果就会称为新promise的结果
const p = new Promise((resolve, reject) => {resolve('ok');
})
let result = p.then(value => {//return value;return new Promise((resolve, reject) => {resolve('okk');})
}, reason => {console.log(reason);
})
console.log(result);
11.5 promise如何串联多个操作任务?
- promise的then()返回一个新的promise对象,可以写成then()方法的链式调用
- 通过then()的链式调用串联多个同步/异步任务
<script>new Promise((resolve, reject) => {console.log(111);reject();}).then(value => {console.log(222);}).then(value=> {console.log(value);}).then(value => {console.log(value)}, reason => {console.error(reason);});
</script>
11.6 promise的异常穿透
- 当使用promise的then链式调用时, 可以在最后指定失败的回调,
- 前面任何操作出了异常, 都会传到最后失败的回调中处理
new Promise((resolve, reject) => {console.log(111);reject('error');
}).then(value => {console.log(222);
}).then(value => {console.log(value);
}).then(value => {console.log(value)
}).catch(reason => {console.log(reason);
})
11.7 中断promise链
- 当使用promise的then链式调用时, 在中间中断, 不再调用后面的回调函数
- 办法: 在回调函数中返回一个pending状态的promise对象
new Promise((resolve, reject) => {console.log(111);resolve('ok');
}).then(value => {console.log(222);
}).then(value => {console.log(value);return new Promise(() => { })
}).then(value => {console.log(value)
}, reason => {console.error(reason);
});
十二、async和await
async/await 是ES7提出的基于Promise的解决异步的最终方案。
12.1 async函数
async是一个加在函数前的修饰符,被async定义的函数会默认返回一个Promise对象resolve的值。
因此对async函数可以直接then,返回值就是then方法传入的函数。
// 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);
12.2 await表达式
await 也是一个修饰符,只能放在async定义的函数内。可以理解为等待。
await 修饰的如果是Promise对象,可以获取Promise中返回的内容(resolve或reject的参数),且取到值后语
句才会往下执行;如果不是Promise对象:把这个非promise的东西当做await表达式的结果。
注意事项
- 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结合await读取文件内容
//1、导包
const fs = require('fs');
const {promisify} = require('util');
//2、将fs.readFile转化成promise风格的函数
const myreadfile = promisify(fs.readFile);
//3、声明async函数
async function main(){try{//4、读取文件let one = await myreadfile('./resource/4.html');let two = await myreadfile('./resource/2.html');let three = await myreadfile('./resource/3.html');//5、拼接读取文件内容console.log(one + two + three);}catch(e){console.log(e);}
}
//6、调用main函数
main();
十三、JS中的宏队列与微队列
- 说明
- JS中用来存储待执行回调函数的队列包含2个不同特定的列队
- 宏列队: 用来保存待执行的宏任务(回调), 比如: 定时器回调/DOM事件回调/ajax回调
- 微列队: 用来保存待执行的微任务(回调), 比如: promise的回调/MutationObserver的回调
- JS执行时会区别这2个队列
- JS引擎首先必须先执行所有的初始化同步任务代码
- 每次准备取出第一个宏任务执行前, 都要将所有的微任务一个一个取出来执行
setTimeout(() => {console.log(111);
});new Promise((resolve, reject) => {resolve();//return ;throwreject();console.log(222);
}).then(v => {console.log(333);
})
console.log(444);
十四、Promise常见面试题
setTimeout(() => {console.log(1)
}, 0)
Promise.resolve().then(() => {console.log(2)
})
Promise.resolve().then(() => {console.log(4)
})
console.log(3)
setTimeout(() => {console.log(1)
}, 0)
new Promise((resolve) => {console.log(2)resolve()
}).then(() => {console.log(3)
}).then(() => {console.log(4)
})
console.log(5)
const first = () => (new Promise((resolve, reject) => {console.log(3)let p = new Promise((resolve, reject) => {console.log(7)setTimeout(() => {console.log(5)resolve(6)}, 0)resolve(1)})resolve(2)p.then((arg) => {console.log(arg)})}))
first().then((arg) => {console.log(arg)
})
console.log(4)
setTimeout(() => {console.log("0")
}, 0)
new Promise((resolve, reject) => {console.log("1")resolve()
}).then(() => {console.log("2")new Promise((resolve, reject) => {console.log("3")resolve()}).then(() => {console.log("4")}).then(() => {console.log("5")})
}).then(() => {console.log("6");
})new Promise((resolve, reject) => {console.log("7")resolve()
}).then(() => {console.log("8")
});
十五、手写promise自定义基础结构的搭建
15.1 Promise 的基本结构
/*** 1- Promise 是一个构造函数* 2- Promise 接收一个参数,该参数的类型是函数(执行器函数executor)* 3- executor接收两个参数(resolve,reject),参数的类型是函数* 4- 执行器函数会同步执行。* 5- then方法在其显式原型属性上*/// 立即调用函数的好处:可以避免对外部的变量造成污染。
(function(window){// executor是执行器函数function Promise(executor){executor(function(){},function(){});}window.Promise = Promise;
})(window);
new Promise((resolve, reject)=>{console.log("这是我的执行器函数",resolve,reject)
})
console.log("over",Promise);
15.2 Promise实例拥有两个实例属性
/** 1- Promise实例拥有两个实例属性:* 状态([[PromiseState]]),初始状态为pending* 值([[PromiseResult]]),初始值为undefined
*/
// 立即调用函数的好处:可以避免对外部的变量造成污染。
(function(window){// executor是执行器函数function Promise(executor){// 定义实例属性state,初始值为pendingthis.state = "pending";// 定义实例属性result,初始值为undefinedthis.result = undefined;executor(function(){},function(){});}window.Promise = Promise;
})(window);
const p1 = new Promise((resolve, reject)=>{console.log("这是我的执行器函数",resolve,reject)
})
console.log(p1);
15.3 更改状态三种方式-方法未抽离
/** 更改状态三种方式* 1- 通过调用resolve将状态更改为成功(fulfilled),接收的值为成功值* 2- 通过调用reject将状态更改为失败(rejected),接收的值为失败值* 3- 抛出异常将状态更改为失败(rejected),失败的值为异常信息。
*/
// 立即调用函数的好处:可以避免对外部的变量造成污染。
(function(window){// executor是执行器函数function Promise(executor){// 定义实例属性state,初始值为pendingthis.state = "pending";// 定义实例属性result,初始值为undefinedthis.result = undefined;try{executor(function(value){// 将状态更改为成功(fulfilled)this.state = "fulfilled";// 成功值为valuethis.result = value;}.bind(this),function(value){// 将状态更改为失败this.state = "rejected";// 将result设置为valuethis.result = value;}.bind(this));}catch (err){// 将状态更改为失败this.state = "rejected";// 将异常信息作为失败值this.result = err;}}window.Promise = Promise;
})(window);
const p1 = new Promise((resolve, reject)=>{// resolve(1);// reject(2);throw "异常"
})
console.log(p1);
15.4 更改状态三种方式-抽离为普通函数
// 立即调用函数的好处:可以避免对外部的变量造成污染。
(function(window){// executor是执行器函数function Promise(executor){// 定义实例属性state,初始值为pendingthis.state = "pending";// 定义实例属性result,初始值为undefinedthis.result = undefined;// 定义resolve函数const _resolve = function(value){// 将状态更改为成功(fulfilled)this.state = "fulfilled";// 成功值为valuethis.result = value;}.bind(this)// 定义reject函数const _reject = function(value){// 将状态更改为失败this.state = "rejected";// 将result设置为valuethis.result = value;}.bind(this)try{executor(_resolve,_reject);}catch (err){// 将状态更改为失败this.state = "rejected";// 将异常信息作为失败值this.result = err;}}window.Promise = Promise;
})(window);
const p1 = new Promise((resolve, reject)=>{// resolve(1);reject(2);// throw "异常"
})
console.log(p1);
15.5 更改状态三种方式-抽离为箭头函数
// 立即调用函数的好处:可以避免对外部的变量造成污染。
(function(window){// executor是执行器函数function Promise(executor){// 定义实例属性state,初始值为pendingthis.state = "pending";// 定义实例属性result,初始值为undefinedthis.result = undefined;// 定义resolve函数const _resolve = value=>{// 将状态更改为成功(fulfilled)this.state = "fulfilled";// 成功值为valuethis.result = value;}// 定义reject函数const _reject = value=>{// 将状态更改为失败this.state = "rejected";// 将result设置为valuethis.result = value;}try{executor(_resolve,_reject);}catch (err){// 将状态更改为失败this.state = "rejected";// 将异常信息作为失败值this.result = err;}}window.Promise = Promise;
})(window);
const p1 = new Promise((resolve, reject)=>{// resolve(1);// reject(2);throw "异常"
})
console.log(p1);
15.6 状态只允许更改一次
/** pending-> fulfilled* pending-> rejected* 改变状态只有这两种,且一个promise对象只能改变一次,,无论变成成功还是失败,都会有一个结果值* 成功的结果数据一般称为value,失败的结果值一般称为reason
*/
// 立即调用函数的好处:可以避免对外部的变量造成污染。
(function(window){// executor是执行器函数function Promise(executor){// 定义实例属性state,初始值为pendingthis.state = "pending";// 定义实例属性result,初始值为undefinedthis.result = undefined;// 定义resolve函数const _resolve = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为成功(fulfilled)this.state = "fulfilled";// 成功值为valuethis.result = value;}// 定义reject函数const _reject = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为失败this.state = "rejected";// 将result设置为valuethis.result = value;}try{executor(_resolve,_reject);}catch (err){_reject(err);// 状态更改为失败,值为异常信息}}window.Promise = Promise;
})(window);
const p1 = new Promise((resolve, reject)=>{resolve(1);reject(2);throw "异常"
})
console.log(p1);
15.7 then函数调用成功或失败回调函数
/** 1- then是Promise中的原型方法* 2- then函数接收两个参数(成功回调,失败回调)* 3- 如果p1状态为成功执行成功回调,失败执行失败回调。
*/
// 立即调用函数的好处:可以避免对外部的变量造成污染。
(function(window){// executor是执行器函数function Promise(executor){// 定义实例属性state,初始值为pendingthis.state = "pending";// 定义实例属性result,初始值为undefinedthis.result = undefined;// 定义resolve函数const _resolve = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为成功(fulfilled)this.state = "fulfilled";// 成功值为valuethis.result = value;}// 定义reject函数const _reject = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为失败this.state = "rejected";// 将result设置为valuethis.result = value;}try{executor(_resolve,_reject);}catch (err){_reject(err);// 状态更改为失败,值为异常信息}}Object.assign(Promise.prototype,{// onResolved:成功回调// onRejected:失败回调then(onResolved,onRejected){// 状态成功调用onResolvedif(this.state === "fulfilled"){onResolved(this.result);}else if(this.state === "rejected"){onRejected(this.result);}},catch(){}})window.Promise = Promise;
})(window);
15.8 then函数中的回调函数是异步调用的
// 立即调用函数的好处:可以避免对外部的变量造成污染。
(function(window){// executor是执行器函数function Promise(executor){// 定义实例属性state,初始值为pendingthis.state = "pending";// 定义实例属性result,初始值为undefinedthis.result = undefined;// 定义resolve函数const _resolve = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为成功(fulfilled)this.state = "fulfilled";// 成功值为valuethis.result = value;}// 定义reject函数const _reject = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为失败this.state = "rejected";// 将result设置为valuethis.result = value;}try{executor(_resolve,_reject);}catch (err){_reject(err);// 状态更改为失败,值为异常信息}}Object.assign(Promise.prototype,{// onResolved:成功回调// onRejected:失败回调then(onResolved,onRejected){// 状态成功调用onResolvedif(this.state === "fulfilled"){// 异步调用setTimeout(()=>{onResolved(this.result);})}else if(this.state === "rejected"){// 异步调用setTimeout(()=>{onRejected(this.result);})}},catch(){}})window.Promise = Promise;
})(window);
const p1 = new Promise((resolve, reject)=>{// resolve(1);// reject(2);throw "异常"
})
p1.then(value=>{console.log("成功回调",value);
},reason=>{console.log("失败回调",reason);
})
console.log("over");
15.9 then函数返回的是一个Promise实例
// 立即调用函数的好处:可以避免对外部的变量造成污染。
(function(window){// executor是执行器函数function Promise(executor){// 定义实例属性state,初始值为pendingthis.state = "pending";// 定义实例属性result,初始值为undefinedthis.result = undefined;// 定义resolve函数const _resolve = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为成功(fulfilled)this.state = "fulfilled";// 成功值为valuethis.result = value;}// 定义reject函数const _reject = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为失败this.state = "rejected";// 将result设置为valuethis.result = value;}try{executor(_resolve,_reject);}catch (err){_reject(err);// 状态更改为失败,值为异常信息}}Object.assign(Promise.prototype,{// onResolved:成功回调// onRejected:失败回调then(onResolved,onRejected){return new Promise((resolve,reject)=>{// 状态成功调用onResolvedif(this.state === "fulfilled"){// 异步调用setTimeout(()=>{onResolved(this.result);})}else if(this.state === "rejected"){// 异步调用setTimeout(()=>{onRejected(this.result);})}})},catch(){}})window.Promise = Promise;
})(window);
const p1 = new Promise((resolve, reject)=>{// resolve(1);// reject(2);throw "异常"
})
const p2 = p1.then(value=>{console.log("成功回调",value);
},reason=>{console.log("失败回调",reason);
})
console.log(p2);
15.10 then函数返回的Promise实例状态以及值-未优化
/** then返回的Promise实例受成功或失败回调函数返回值的影响* 1- 如果返回的是非Promise,那么p2状态为成功,值为返回值* 2- 如果返回的是Promise,那么p2状态以及值与返回的状态,值相同。* 3- 如果出现异常,那么p2状态为失败,值为异常信息。
*/
// 立即调用函数的好处:可以避免对外部的变量造成污染。
(function(window){// executor是执行器函数function Promise(executor){// 定义实例属性state,初始值为pendingthis.state = "pending";// 定义实例属性result,初始值为undefinedthis.result = undefined;// 定义resolve函数const _resolve = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为成功(fulfilled)this.state = "fulfilled";// 成功值为valuethis.result = value;}// 定义reject函数const _reject = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为失败this.state = "rejected";// 将result设置为valuethis.result = value;}try{executor(_resolve,_reject);}catch (err){_reject(err);// 状态更改为失败,值为异常信息}}Object.assign(Promise.prototype,{// onResolved:成功回调// onRejected:失败回调then(onResolved,onRejected){return new Promise((resolve,reject)=>{// 状态成功调用onResolvedif(this.state === "fulfilled"){// 异步调用setTimeout(()=>{try{// value是成功回调的返回值const value = onResolved(this.result);// 判断value是不是通过Promise实例化出来的(判断value是否为Promise实例)if(value instanceof Promise){// value.then(v=>{// // 将返回的Promise实例设置为成功,值为v// resolve(v);// },s=>{// // 将返回的Promise实例设置为失败,值为s// reject(s);// })// 简化:value.then(resolve,reject)}else{// 不是Promise实例,将返回的Promise状态设置为成功,值为valueresolve(value);}}catch (err){// 有异常,将返回Promise的状态更改为失败,值为errreject(err);}})}else if(this.state === "rejected"){// 异步调用setTimeout(()=>{try{// value是失败回调的返回值const value = onRejected(this.result);// value是否为Promise实例if(value instanceof Promise){// 将返回Promise设置为与value相同的结果value.then(resolve,reject);}else{// 返回成功promise,值为valueresolve(value);}}catch (err){// 返回失败promise,值为errreject(err);}})}})},catch(){}})window.Promise = Promise;
})(window);
const p1 = new Promise((resolve, reject)=>{// resolve(1);reject(2);// throw "异常"
})
const p2 = p1.then(value=>{return new Promise((resolve,reject)=>{// resolve(100)// reject(200)throw "异常2"})// return 1;// console.log("成功回调",value);
},reason=>{return new Promise((resolve,reject)=>{// resolve(100);// reject(2)throw "异常3"})// return 1;// console.log("失败回调",reason);
})
console.log(p2);
15.11 then函数返回的Promise实例状态以及值-优化封装函数_common
// 立即调用函数的好处:可以避免对外部的变量造成污染。
(function(window){// executor是执行器函数function Promise(executor){// 定义实例属性state,初始值为pendingthis.state = "pending";// 定义实例属性result,初始值为undefinedthis.result = undefined;// 定义resolve函数const _resolve = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为成功(fulfilled)this.state = "fulfilled";// 成功值为valuethis.result = value;}// 定义reject函数const _reject = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为失败this.state = "rejected";// 将result设置为valuethis.result = value;}try{executor(_resolve,_reject);}catch (err){_reject(err);// 状态更改为失败,值为异常信息}}Object.assign(Promise.prototype,{// onResolved:成功回调// onRejected:失败回调then(onResolved,onRejected){return new Promise((resolve,reject)=>{const _common = function(callback){setTimeout(()=>{try{// value是成功回调的返回值const value = callback(this.result);// 判断value是不是通过Promise实例化出来的(判断value是否为Promise实例)if(value instanceof Promise){value.then(resolve,reject);}else{// 不是Promise实例,将返回的Promise状态设置为成功,值为valueresolve(value);}}catch (err){// 有异常,将返回Promise的状态更改为失败,值为errreject(err);}})}// 状态成功调用onResolved// p1的状态为成功if(this.state === "fulfilled"){_common.call(this,onResolved);}else if(this.state === "rejected"){_common.call(this,onRejected);}})},catch(){}})window.Promise = Promise;
})(window);
const p1 = new Promise((resolve, reject)=>{// resolve(1);reject(2);// throw "异常"
})
const p2 = p1.then(value=>{// return new Promise((resolve,reject)=>{// // resolve(100)// // reject(200)throw "异常2"// })// return 1;// console.log("成功回调",value);
},reason=>{// return new Promise((resolve,reject)=>{// // resolve(100);// // reject(2)// throw "异常3"// })// return 1;// console.log("失败回调",reason);
})
console.log(p2);
15.12 增加成功与失败回调函数的默认值
/** 1- then如果省略成功回调,默认成功回调为 value=>value;* 2- then如果省略失败回调,默认失败回调为 reason=>{throw reason};
*/
// 立即调用函数的好处:可以避免对外部的变量造成污染。
(function(window){// executor是执行器函数function Promise(executor){// 定义实例属性state,初始值为pendingthis.state = "pending";// 定义实例属性result,初始值为undefinedthis.result = undefined;// 定义resolve函数const _resolve = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为成功(fulfilled)this.state = "fulfilled";// 成功值为valuethis.result = value;}// 定义reject函数const _reject = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为失败this.state = "rejected";// 将result设置为valuethis.result = value;}try{executor(_resolve,_reject);}catch (err){_reject(err);// 状态更改为失败,值为异常信息}}Object.assign(Promise.prototype,{// onResolved:成功回调// onRejected:失败回调then(onResolved,onRejected){// 如果成功回调不是函数,那么增加成功回调默认值if(!(onResolved instanceof Function)){onResolved = value=>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.result);// 判断value是不是通过Promise实例化出来的(判断value是否为Promise实例)if(value instanceof Promise){value.then(resolve,reject);}else{// 不是Promise实例,将返回的Promise状态设置为成功,值为valueresolve(value);}}catch (err){// 有异常,将返回Promise的状态更改为失败,值为errreject(err);}})}// 状态成功调用onResolved// p1的状态为成功if(this.state === "fulfilled"){_common.call(this,onResolved);}else if(this.state === "rejected"){_common.call(this,onRejected);}})},catch(){}})window.Promise = Promise;
})(window);
const p1 = new Promise((resolve,reject)=>{resolve(1);// reject(2);
})
const p2 = p1.then();
console.log(p2);
15.14 执行器函数常用于处理异步行为
(function(window){// executor是执行器函数function Promise(executor){// 记录成功与失败回调函数this.callbackFn = {};// 定义实例属性state,初始值为pendingthis.state = "pending";// 定义实例属性result,初始值为undefinedthis.result = undefined;// 定义resolve函数const _resolve = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为成功(fulfilled)this.state = "fulfilled";// 成功值为valuethis.result = value;if(this.callbackFn.onResolved){this.callbackFn.onResolved();}}// 定义reject函数const _reject = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为失败this.state = "fulfilled";// 将result设置为valuethis.result = value;if(this.callbackFn.onRejected){this.callbackFn.onRejected();}}try{executor(_resolve,_reject);}catch (err){_reject(err);// 状态更改为失败,值为异常信息}}Object.assign(Promise.prototype,{// onResolved:成功回调// onRejected:失败回调then(onResolved,onRejected){// 如果成功回调不是函数,那么增加成功回调默认值if(!(onResolved instanceof Function)){onResolved = value=>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.result);// 判断value是不是通过Promise实例化出来的(判断value是否为Promise实例)if(value instanceof Promise) value.then(resolve,reject);else{// 不是Promise实例,将返回的Promise状态设置为成功,值为valueresolve(value);}}catch (err){// 有异常,将返回Promise的状态更改为失败,值为errreject(err);}})}// 状态成功调用onResolved// p1的状态为成功if(this.state === "fulfilled"){_common.call(this,onResolved);}else if(this.state === "rejected"){_common.call(this,onRejected);}else{// pending// 如果状态为pending,那么保存成功与失败回调this.callbackFn = {onResolved:_common.bind(this,onResolved),onRejected:_common.bind(this,onRejected)}}})},catch(){}})window.Promise = Promise;
})(window);
const p1 = new Promise((resolve,reject)=>{setTimeout(()=>{reject(100);})
})
p1.then(value=>{console.log(value);
},reason=>{console.log("失败",reason);
})
15.15 可以指定多个成功或失败的回调
(function(window){// executor是执行器函数function Promise(executor){// 记录成功与失败回调函数this.callbackFn = [];// 定义实例属性state,初始值为pendingthis.state = "pending";// 定义实例属性result,初始值为undefinedthis.result = undefined;// 定义resolve函数const _resolve = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为成功(fulfilled)this.state = "fulfilled";// 成功值为valuethis.result = value;this.callbackFn.forEach(item=>{item.onResolved()})}// 定义reject函数const _reject = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为失败this.state = "fulfilled";// 将result设置为valuethis.result = value;this.callbackFn.forEach(item=>{item.onRejected()})}try{executor(_resolve,_reject);}catch (err){_reject(err);// 状态更改为失败,值为异常信息}}Object.assign(Promise.prototype,{// onResolved:成功回调// onRejected:失败回调then(onResolved,onRejected){// 如果成功回调不是函数,那么增加成功回调默认值if(!(onResolved instanceof Function)){onResolved = value=>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.result);// 判断value是不是通过Promise实例化出来的(判断value是否为Promise实例)if(value instanceof Promise) value.then(resolve,reject);else{// 不是Promise实例,将返回的Promise状态设置为成功,值为valueresolve(value);}}catch (err){// 有异常,将返回Promise的状态更改为失败,值为errreject(err);}})}// 状态成功调用onResolved// p1的状态为成功if(this.state === "fulfilled"){_common.call(this,onResolved);}else if(this.state === "rejected"){_common.call(this,onRejected);}else{// pending// 如果状态为pending,那么保存成功与失败回调this.callbackFn.push({onResolved:_common.bind(this,onResolved),onRejected:_common.bind(this,onRejected)})}})},catch(){}})window.Promise = Promise;
})(window);
// 可以指定多个成功或失败的回调
const p1 = new Promise((resolve,reject)=>{setTimeout(()=>{reject(100);})
})
p1.then(value=>{console.log("成功1",value);
},reason=>{console.log("失败1",reason);
})
p1.then(value=>{console.log("成功2",value);
},reason=>{console.log("失败2",reason);
})
p1.then(value=>{console.log("成功3",value);
},reason=>{console.log("失败3",reason);
})
p1.then(value=>{console.log("成功4",value);
},reason=>{console.log("失败4",reason);
})
15.16 catch
(function(window){// executor是执行器函数function Promise(executor){// 记录成功与失败回调函数this.callbackFn = [];// 定义实例属性state,初始值为pendingthis.state = "pending";// 定义实例属性result,初始值为undefinedthis.result = undefined;// 定义resolve函数const _resolve = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为成功(fulfilled)this.state = "fulfilled";// 成功值为valuethis.result = value;this.callbackFn.forEach(item=>{item.onResolved()})}// 定义reject函数const _reject = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为失败this.state = "fulfilled";// 将result设置为valuethis.result = value;this.callbackFn.forEach(item=>{item.onRejected()})}try{executor(_resolve,_reject);}catch (err){_reject(err);// 状态更改为失败,值为异常信息}}Object.assign(Promise.prototype,{// onResolved:成功回调// onRejected:失败回调then(onResolved,onRejected){// 如果成功回调不是函数,那么增加成功回调默认值if(!(onResolved instanceof Function)){onResolved = value=>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.result);// 判断value是不是通过Promise实例化出来的(判断value是否为Promise实例)if(value instanceof Promise) value.then(resolve,reject);else{// 不是Promise实例,将返回的Promise状态设置为成功,值为valueresolve(value);}}catch (err){// 有异常,将返回Promise的状态更改为失败,值为errreject(err);}})}// 状态成功调用onResolved// p1的状态为成功if(this.state === "fulfilled"){_common.call(this,onResolved);}else if(this.state === "rejected"){_common.call(this,onRejected);}else{// pending// 如果状态为pending,那么保存成功与失败回调this.callbackFn.push({onResolved:_common.bind(this,onResolved),onRejected:_common.bind(this,onRejected)})}})},catch(onRejected){return this.then(undefined,onRejected)}})window.Promise = Promise;
})(window);
// 可以指定多个成功或失败的回调
const p1 = new Promise((resolve,reject)=>{setTimeout(()=>{reject(100);})
})
// p1.then(undefined,reason=>{
// console.log(reason);
// })
// catch的返回值是Promise实例,实例的属性与值取决于回调函数的返回值
// 返回值为非Promise实例,那么得到的状态为成功,值为返回值
// 返回值为Promise实例,那么得到的结果与返回的结果相同。
// 有异常,那么得到的状态为失败,值为异常信息。
const p2 = p1.catch(reason=>{// console.log(reason);return new Promise((resolve,reject)=>{resolve(2);})// throw "异常"
})
console.log(p2);
15.17 链式调用支持
(function(window){// executor是执行器函数function Promise(executor){// 记录成功与失败回调函数this.callbackFn = [];// 定义实例属性state,初始值为pendingthis.state = "pending";// 定义实例属性result,初始值为undefinedthis.result = undefined;// 定义resolve函数const _resolve = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为成功(fulfilled)this.state = "fulfilled";// 成功值为valuethis.result = value;this.callbackFn.forEach(item=>{item.onResolved()})}// 定义reject函数const _reject = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为失败this.state = "rejected";// 将result设置为valuethis.result = value;this.callbackFn.forEach(item=>{item.onRejected()})}try{executor(_resolve,_reject);}catch (err){_reject(err);// 状态更改为失败,值为异常信息}}Object.assign(Promise.prototype,{// onResolved:成功回调// onRejected:失败回调then(onResolved,onRejected){// 如果成功回调不是函数,那么增加成功回调默认值if(!(onResolved instanceof Function)){onResolved = value=>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.result);// 判断value是不是通过Promise实例化出来的(判断value是否为Promise实例)if(value instanceof Promise) value.then(resolve,reject);else{// 不是Promise实例,将返回的Promise状态设置为成功,值为valueresolve(value);}}catch (err){// 有异常,将返回Promise的状态更改为失败,值为errreject(err);}})}// 状态成功调用onResolved// p1的状态为成功if(this.state === "fulfilled"){_common.call(this,onResolved);}else if(this.state === "rejected"){_common.call(this,onRejected);}else{// pending// 如果状态为pending,那么保存成功与失败回调this.callbackFn.push({onResolved:_common.bind(this,onResolved),onRejected:_common.bind(this,onRejected)})}})},catch(onRejected){return this.then(undefined,onRejected)}})window.Promise = Promise;
})(window);
new Promise((resolve,reject)=>{resolve(1);
}).then(value=>{console.log(value);// 1return 2;
}).then(value=>{console.log(value);// 2return 3;
}).then(value=>{console.log(value);// 3return 4;
}).then(value=>{console.log(value);// 4return 5;
})
15.18 异常穿透支持
(function(window){// executor是执行器函数function Promise(executor){// 记录成功与失败回调函数this.callbackFn = [];// 定义实例属性state,初始值为pendingthis.state = "pending";// 定义实例属性result,初始值为undefinedthis.result = undefined;// 定义resolve函数const _resolve = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为成功(fulfilled)this.state = "fulfilled";// 成功值为valuethis.result = value;this.callbackFn.forEach(item=>{item.onResolved()})}// 定义reject函数const _reject = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为失败this.state = "rejected";// 将result设置为valuethis.result = value;this.callbackFn.forEach(item=>{item.onRejected()})}try{executor(_resolve,_reject);}catch (err){_reject(err);// 状态更改为失败,值为异常信息}}Object.assign(Promise.prototype,{// onResolved:成功回调// onRejected:失败回调then(onResolved,onRejected){// 如果成功回调不是函数,那么增加成功回调默认值if(!(onResolved instanceof Function)){onResolved = value=>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.result);// 判断value是不是通过Promise实例化出来的(判断value是否为Promise实例)if(value instanceof Promise) value.then(resolve,reject);else{// 不是Promise实例,将返回的Promise状态设置为成功,值为valueresolve(value);}}catch (err){// 有异常,将返回Promise的状态更改为失败,值为errreject(err);}})}// 状态成功调用onResolved// p1的状态为成功if(this.state === "fulfilled"){_common.call(this,onResolved);}else if(this.state === "rejected"){_common.call(this,onRejected);}else{// pending// 如果状态为pending,那么保存成功与失败回调this.callbackFn.push({onResolved:_common.bind(this,onResolved),onRejected:_common.bind(this,onRejected)})}})},catch(onRejected){return this.then(undefined,onRejected)}})window.Promise = Promise;
})(window);
new Promise((resolve, reject) => {resolve(1);
}).then(value => {throw "异常"
}).then(value => {console.log(value);return 3;
}).then(value => {console.log(value);// 3return 4;
}).then(value => {console.log(value);// 4return 5;
}).catch(reason => {console.log(4,reason);
})
15.19 中断Promise链
(function(window){// executor是执行器函数function Promise(executor){// 记录成功与失败回调函数this.callbackFn = [];// 定义实例属性state,初始值为pendingthis.state = "pending";// 定义实例属性result,初始值为undefinedthis.result = undefined;// 定义resolve函数const _resolve = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为成功(fulfilled)this.state = "fulfilled";// 成功值为valuethis.result = value;this.callbackFn.forEach(item=>{item.onResolved()})}// 定义reject函数const _reject = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为失败this.state = "rejected";// 将result设置为valuethis.result = value;this.callbackFn.forEach(item=>{item.onRejected()})}try{executor(_resolve,_reject);}catch (err){_reject(err);// 状态更改为失败,值为异常信息}}Object.assign(Promise.prototype,{// onResolved:成功回调// onRejected:失败回调then(onResolved,onRejected){// 如果成功回调不是函数,那么增加成功回调默认值if(!(onResolved instanceof Function)){onResolved = value=>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.result);// 判断value是不是通过Promise实例化出来的(判断value是否为Promise实例)if(value instanceof Promise) value.then(resolve,reject);else{// 不是Promise实例,将返回的Promise状态设置为成功,值为valueresolve(value);}}catch (err){// 有异常,将返回Promise的状态更改为失败,值为errreject(err);}})}// 状态成功调用onResolved// p1的状态为成功if(this.state === "fulfilled"){_common.call(this,onResolved);}else if(this.state === "rejected"){_common.call(this,onRejected);}else{// pending// 如果状态为pending,那么保存成功与失败回调this.callbackFn.push({onResolved:_common.bind(this,onResolved),onRejected:_common.bind(this,onRejected)})}})},catch(onRejected){return this.then(undefined,onRejected)}})window.Promise = Promise;
})(window);
new Promise((resolve,reject)=>{resolve(1);
}).then(value=>{console.log(value);// 1return 2;
}).then(value=>{console.log(value);// 2// 在回调函数中返回一个`pendding`状态的promise对象return new Promise(()=>{})
}).then(value=>{console.log(value);// undefinedreturn 4;
}).then(value=>{console.log(value);// 4return 5;
})
15.20 resolve
(function(window){// executor是执行器函数function Promise(executor){// 记录成功与失败回调函数this.callbackFn = [];// 定义实例属性state,初始值为pendingthis.state = "pending";// 定义实例属性result,初始值为undefinedthis.result = undefined;// 定义resolve函数const _resolve = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为成功(fulfilled)this.state = "fulfilled";// 成功值为valuethis.result = value;this.callbackFn.forEach(item=>{item.onResolved()})}// 定义reject函数const _reject = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为失败this.state = "rejected";// 将result设置为valuethis.result = value;this.callbackFn.forEach(item=>{item.onRejected()})}try{executor(_resolve,_reject);}catch (err){_reject(err);// 状态更改为失败,值为异常信息}}Object.assign(Promise.prototype,{// onResolved:成功回调// onRejected:失败回调then(onResolved,onRejected){// 如果成功回调不是函数,那么增加成功回调默认值if(!(onResolved instanceof Function)){onResolved = value=>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.result);// 判断value是不是通过Promise实例化出来的(判断value是否为Promise实例)if(value instanceof Promise) value.then(resolve,reject);else{// 不是Promise实例,将返回的Promise状态设置为成功,值为valueresolve(value);}}catch (err){// 有异常,将返回Promise的状态更改为失败,值为errreject(err);}})}// 状态成功调用onResolved// p1的状态为成功if(this.state === "fulfilled"){_common.call(this,onResolved);}else if(this.state === "rejected"){_common.call(this,onRejected);}else{// pending// 如果状态为pending,那么保存成功与失败回调this.callbackFn.push({onResolved:_common.bind(this,onResolved),onRejected:_common.bind(this,onRejected)})}})},catch(onRejected){return this.then(undefined,onRejected)}})Promise.resolve = function(value){if(value instanceof Promise){return value;// 如果是Promise实例直接返回}else{// 如果不是Promise实例,那么返回的状态为成功,值为valuereturn new Promise(resolve=>{resolve(value);})}}window.Promise = Promise;
})(window);
// const p1 = Promise.resolve(1);
// console.log(p1);// const p1 = Promise.resolve(new Promise((resolve,reject)=>{
// resolve(2);
// }));
// console.log(p1);
//
// const p1 = Promise.resolve(new Promise((resolve,reject)=>{
// reject(2);
// }));
// console.log(p1);const p =new Promise((resolve,reject)=>{reject(2);
})
const p1 = Promise.resolve(p);
console.log(p1===p);
15.21 reject
(function(window){// executor是执行器函数function Promise(executor){// 记录成功与失败回调函数this.callbackFn = [];// 定义实例属性state,初始值为pendingthis.state = "pending";// 定义实例属性result,初始值为undefinedthis.result = undefined;// 定义resolve函数const _resolve = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为成功(fulfilled)this.state = "fulfilled";// 成功值为valuethis.result = value;this.callbackFn.forEach(item=>{item.onResolved()})}// 定义reject函数const _reject = value=>{// 当状态已经被更改过,不允许再次更改if(this.state !== "pending") return;// 将状态更改为失败this.state = "rejected";// 将result设置为valuethis.result = value;this.callbackFn.forEach(item=>{item.onRejected()})}try{executor(_resolve,_reject);}catch (err){_reject(err);// 状态更改为失败,值为异常信息}}Object.assign(Promise.prototype,{// onResolved:成功回调// onRejected:失败回调then(onResolved,onRejected){// 如果成功回调不是函数,那么增加成功回调默认值if(!(onResolved instanceof Function)){onResolved = value=>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.result);// 判断value是不是通过Promise实例化出来的(判断value是否为Promise实例)if(value instanceof Promise) value.then(resolve,reject);else{// 不是Promise实例,将返回的Promise状态设置为成功,值为valueresolve(value);}}catch (err){// 有异常,将返回Promise的状态更改为失败,值为errreject(err);}})}// 状态成功调用onResolved// p1的状态为成功if(this.state === "fulfilled"){_common.call(this,onResolved);}else if(this.state === "rejected"){_common.call(this,onRejected);}else{// pending// 如果状态为pending,那么保存成功与失败回调this.callbackFn.push({onResolved:_common.bind(this,onResolved),onRejected:_common.bind(this,onRejected)})}})},catch(onRejected){return this.then(undefined,onRejected)}})Promise.resolve = function(value){if(value instanceof Promise){return value;// 如果是Promise实例直接返回}else{// 如果不是Promise实例,那么返回的状态为成功,值为valuereturn new Promise(resolve=>{resolve(value);})}}Promise.reject = function(value){return new Promise((resolve,reject)=>{reject(value);})}window.Promise = Promise;
})(window);
const p1 = Promise.reject(1);
console.log(p1);const p2 = Promise.reject(new Promise((resolve,reject)=>{resolve(2);
}));
console.log(p2);const p3 = Promise.reject(new Promise((resolve,reject)=>{reject(2);
}));
console.log(p3);
15.22 完成all
(function (window) {// 接收执行器函数(executor),执行器函数会同步执行(立即执行)。function Promise(executor) {this.state = "pending";// 初始状态this.result = undefined;// 初始值this.callbackFn = [];// _resolve函数将状态更新为成功,成功值为接收的valueconst _resolve = value => {// 如果状态已经更改,直接跳出函数体if (this.state !== "pending") return;this.state = "fulfilled";// 状态更新为成功this.result = value;// 更新成功值this.callbackFn.forEach(item=>{item.onResolved();})}// _reject函数将状态更新为失败,失败值为接收的valueconst _reject = value => {// 如果状态已经更改,直接跳出函数体if (this.state !== "pending") return;this.state = "rejected";// 状态更新为失败this.result = value;// 更新失败值this.callbackFn.forEach(item=>{item.onRejected();})}try {executor(_resolve, _reject);} catch (err) {// 如果有异常,将状态更新为失败,失败的值为异常信息_reject(err);}}// 将第二个参数(对象)合并至Promise.prototype对象中。Object.assign(Promise.prototype, {// 1- 接收成功与失败回调函数// 2- 返回的是一个Promise实例// 3- onResolved成功回调,默认值为value=>value;// 4- onRejected失败回调,默认值为reason=>{throw reason};then(onResolved, onRejected) {// onResolved成功回调,默认值为value=>value;if (!(onResolved instanceof Function)) onResolved = value => value;//onRejected失败回调,默认值为reason=>{throw reason};if (!(onRejected instanceof Function)) onRejected = reason => {throw reason};return new Promise((resolve, reject) => {// callback是成功或失败回调const _common = function (callback) {setTimeout(()=>{try {// value是成功回调返回结果const value = callback(this.result);// 判断是否为Promise实例if (value instanceof Promise) {value.then(resolve, reject);} else {// 非Promise实例resolve(value);}} catch (err) {reject(err);}})}// 判断状态为成功,调用成功回调if (this.state === "fulfilled") _common.call(this, onResolved);else if (this.state === "rejected") _common.call(this, onRejected);else {this.callbackFn.push({onResolved: _common.bind(this, onResolved),onRejected: _common.bind(this, onRejected)})}})},catch(onRejected){return this.then(undefined,onRejected);}})Promise.resolve = function(value){// 判断接收的参数是否为Promise实例,如果是直接返回if(value instanceof Promise){return value;}else{// 如果不是,创建一个新的Promise,状态为成功,值为value;return new Promise(resolve=>{resolve(value);})}}Promise.reject = function(value){// 返回失败的Promise,失败值为接收的valuereturn new Promise((resolve,reject)=>{reject(value);})}// 1- 接收的是数组,返回的是PromisePromise.all = function(promiseArr){let index = 0;let successArr = new Array(promiseArr.length);return new Promise((resolve,reject)=>{promiseArr.forEach((value,i)=>{value.then(v=>{index++;successArr[i] = v;if(index === promiseArr.length){resolve(successArr);}},s=>{// 返回Promise的状态设置失败reject(s);})})})}window.Promise = Promise;
})(window);
const p1 = new Promise((resolve,reject)=>{setTimeout(()=>{resolve(100)},100)
})
const p2 = new Promise((resolve,reject)=>{setTimeout(()=>{resolve(200)},50)
})
const p3 = new Promise((resolve,reject)=>{setTimeout(()=>{resolve(300)},200)
})
const p4 = new Promise((resolve,reject)=>{setTimeout(()=>{resolve(400)},100)
})
// all接收的数组中的元素是Promise实例。
// 元素中的Promise实例都成功,p的状态为成功,值为数组,数组的元素为成功值
// 元素中有一个失败,那么p的状态为失败,值为失败值
const p = Promise.all([p1,p2,p3,p4]);
console.log(p);
15.23 完成race
(function (window) {// 接收执行器函数(executor),执行器函数会同步执行(立即执行)。function Promise(executor) {this.state = "pending";// 初始状态this.result = undefined;// 初始值this.callbackFn = [];// _resolve函数将状态更新为成功,成功值为接收的valueconst _resolve = value => {// 如果状态已经更改,直接跳出函数体if (this.state !== "pending") return;this.state = "fulfilled";// 状态更新为成功this.result = value;// 更新成功值this.callbackFn.forEach(item=>{item.onResolved();})}// _reject函数将状态更新为失败,失败值为接收的valueconst _reject = value => {// 如果状态已经更改,直接跳出函数体if (this.state !== "pending") return;this.state = "rejected";// 状态更新为失败this.result = value;// 更新失败值this.callbackFn.forEach(item=>{item.onRejected();})}try {executor(_resolve, _reject);} catch (err) {// 如果有异常,将状态更新为失败,失败的值为异常信息_reject(err);}}// 将第二个参数(对象)合并至Promise.prototype对象中。Object.assign(Promise.prototype, {// 1- 接收成功与失败回调函数// 2- 返回的是一个Promise实例// 3- onResolved成功回调,默认值为value=>value;// 4- onRejected失败回调,默认值为reason=>{throw reason};then(onResolved, onRejected) {// onResolved成功回调,默认值为value=>value;if (!(onResolved instanceof Function)) onResolved = value => value;//onRejected失败回调,默认值为reason=>{throw reason};if (!(onRejected instanceof Function)) onRejected = reason => {throw reason};return new Promise((resolve, reject) => {// callback是成功或失败回调const _common = function (callback) {setTimeout(()=>{try {// value是成功回调返回结果const value = callback(this.result);// 判断是否为Promise实例if (value instanceof Promise) {value.then(resolve, reject);} else {// 非Promise实例resolve(value);}} catch (err) {reject(err);}})}// 判断状态为成功,调用成功回调if (this.state === "fulfilled") _common.call(this, onResolved);else if (this.state === "rejected") _common.call(this, onRejected);else {this.callbackFn.push({onResolved: _common.bind(this, onResolved),onRejected: _common.bind(this, onRejected)})}})},catch(onRejected){return this.then(undefined,onRejected);}})Promise.resolve = function(value){// 判断接收的参数是否为Promise实例,如果是直接返回if(value instanceof Promise){return value;}else{// 如果不是,创建一个新的Promise,状态为成功,值为value;return new Promise(resolve=>{resolve(value);})}}Promise.reject = function(value){// 返回失败的Promise,失败值为接收的valuereturn new Promise((resolve,reject)=>{reject(value);})}// 1- 接收的是数组,返回的是PromisePromise.all = function(promiseArr){let index = 0;let successArr = new Array(promiseArr.length);return new Promise((resolve,reject)=>{promiseArr.forEach((value,i)=>{value.then(v=>{index++;successArr[i] = v;if(index === promiseArr.length){resolve(successArr);}},s=>{// 返回Promise的状态设置失败reject(s);})})})}Promise.race = function(promiseArr){return new Promise((resolve,reject)=>{promiseArr.forEach(value=>{// value.then(v=>{// resolve(v);// },s=>{// reject(s);// })value.then(resolve,reject);})})}window.Promise = Promise;
})(window);
const p1 = new Promise((resolve,reject)=>{setTimeout(()=>{resolve(100)},100)
})
const p2 = new Promise((resolve,reject)=>{setTimeout(()=>{reject(200)},50)
})
const p3 = new Promise((resolve,reject)=>{setTimeout(()=>{resolve(300)},200)
})
const p4 = new Promise((resolve,reject)=>{setTimeout(()=>{resolve(400)},100)
})
// race:返回的是Promise实例,谁先执行完就与谁的状态以及值相同。
const p = Promise.race([p1,p2,p3,p4]);
console.log(p);
15.24 class版本实现Promise
(function (window) {// 1-将之前构造函数体内的语句放置到constructor函数中// 2-将之前prototype的属性直接放置到Promise中class Promise{static resolve(value){// 判断接收的参数是否为Promise实例,如果是直接返回if(value instanceof Promise){return value;}else{// 如果不是,创建一个新的Promise,状态为成功,值为value;return new Promise(resolve=>{resolve(value);})}}static reject(value){// 返回失败的Promise,失败值为接收的valuereturn new Promise((resolve,reject)=>{reject(value);})}static all(promiseArr){let index = 0;let successArr = new Array(promiseArr.length);return new Promise((resolve,reject)=>{promiseArr.forEach((value,i)=>{value.then(v=>{index++;successArr[i] = v;if(index === promiseArr.length){resolve(successArr);}},s=>{// 返回Promise的状态设置失败reject(s);})})})}static race(promiseArr){return new Promise((resolve,reject)=>{promiseArr.forEach(value=>{// value.then(v=>{// resolve(v);// },s=>{// reject(s);// })value.then(resolve,reject);})})}constructor(executor) {this.state = "pending";// 初始状态this.result = undefined;// 初始值this.callbackFn = [];// _resolve函数将状态更新为成功,成功值为接收的valueconst _resolve = value => {// 如果状态已经更改,直接跳出函数体if (this.state !== "pending") return;this.state = "fulfilled";// 状态更新为成功this.result = value;// 更新成功值this.callbackFn.forEach(item=>{item.onResolved();})}// _reject函数将状态更新为失败,失败值为接收的valueconst _reject = value => {// 如果状态已经更改,直接跳出函数体if (this.state !== "pending") return;this.state = "rejected";// 状态更新为失败this.result = value;// 更新失败值this.callbackFn.forEach(item=>{item.onRejected();})}try {executor(_resolve, _reject);} catch (err) {// 如果有异常,将状态更新为失败,失败的值为异常信息_reject(err);}}then(onResolved, onRejected) {// onResolved成功回调,默认值为value=>value;if (!(onResolved instanceof Function)) onResolved = value => value;//onRejected失败回调,默认值为reason=>{throw reason};if (!(onRejected instanceof Function)) onRejected = reason => {throw reason};return new Promise((resolve, reject) => {// callback是成功或失败回调const _common = function (callback) {setTimeout(()=>{try {// value是成功回调返回结果const value = callback(this.result);// 判断是否为Promise实例if (value instanceof Promise) {value.then(resolve, reject);} else {// 非Promise实例resolve(value);}} catch (err) {reject(err);}})}// 判断状态为成功,调用成功回调if (this.state === "fulfilled") _common.call(this, onResolved);else if (this.state === "rejected") _common.call(this, onRejected);else {this.callbackFn.push({onResolved: _common.bind(this, onResolved),onRejected: _common.bind(this, onRejected)})}})}catch(onRejected){return this.then(undefined,onRejected);}}window.Promise = Promise;
})(window);
const p1 = new Promise((resolve,reject)=>{setTimeout(()=>{resolve(100)},100)
})
const p2 = new Promise((resolve,reject)=>{setTimeout(()=>{reject(200)},50)
})
const p3 = new Promise((resolve,reject)=>{setTimeout(()=>{resolve(300)},200)
})
const p4 = new Promise((resolve,reject)=>{setTimeout(()=>{resolve(400)},100)
})
// race:返回的是Promise实例,谁先执行完就与谁的状态以及值相同。
const p = Promise.race([p1,p2,p3,p4]);
console.log(p);
相关文章:
尚硅谷2023版Promise教程从入门到实战(讲师:任安萍)
一、前言:为什么会出现Promise? Promise的重要性我认为没有必要多讲,概括起来说就是五个字:必!须!得!掌!握!。 而且还要掌握透彻,在实际的使用中,有非常多…...
【SpringBoot】分组校验和自定义校验
分组检验 参数校验时,我们希望不同的方法参数校验规则不同,这时就需要分组校验。 public class Category {NotNull(groups Update.class)private Integer id;//主键IDNotEmptyprivate String categoryName;//分类名称// NotEmpty(groups {Add.class,…...
19、BLIP-2
简介 github 通过利用预训练的视觉模型和语言模型来提升多模态效果和降低训练成本,预训练的视觉模型能够提供高质量的视觉表征,预训练的语言模型则提供了强大的语言生成能力。 实现过程 为了弥合模态差距,提出了一个分两个阶段预训练的 Qu…...
【微服务核心】MyBatis Plus
文章目录 1. 简介2. 入门使用3. 核心功能3.1 CRUD 接口3.1.1 Mapper CRUD 接口3.1.2 Service CRUD 接口 3.2 条件构造器3.3 分页插件3.4 Mybatis-Plus 注解 4. 拓展4.1 逻辑删除4.2 MybatisX快速开发插件 5. 插件5.1 [分页插件](#page)5.2 乐观锁插件 1. 简介 MyBatis Plus&am…...
什么是Alibaba Cloud Linux?完全兼容CentOS,详细介绍
Alibaba Cloud Linux是基于龙蜥社区OpenAnolis龙蜥操作系统Anolis OS的阿里云发行版,针对阿里云服务器ECS做了大量深度优化,Alibaba Cloud Linux由阿里云官方免费提供长期支持和维护LTS,Alibaba Cloud Linux完全兼容CentOS/RHEL生态和操作方式…...
Spark---RDD算子(单值类型Value)
文章目录 1.RDD算子介绍2.转换算子2.1 Value类型2.1.1 map2.1.2 mapPartitions2.1.3 mapPartitionsWithIndex2.1.4 flatMap2.1.5 glom2.1.6 groupBy2.1.7 filter2.1.8 sample2.1.9 distinct2.1.10 coalesce2.1.11 repartition2.1.12 sortBy 1.RDD算子介绍 RDD算子是用于对RDD进…...
数据库中的MVCC--多版本并发控制
一、前言 1、定义:MVCC(Multi-Version Concurrency Control),多版本并发控制,主要为了提高数据库 的并发性能。是MySQL的InnoDB存储引擎实现隔离级别的一种具体方式。用于实现提交读和可重 复读这两种隔离级别。 2…...
wps将姓名处理格式为:姓**
1.打开wps,在要处理数据右侧一个单元格 输入公式:LEFT(A1,1)&"**",然后回车 2.按住ctrl和处理好的数据的右下角小方框,往下拖动即可生成格式为:姓** 格式的数据 3.复制生成的数据,右键选择 “…...
2023年我的编程之旅:技术演进与自我成长的纪录
2023年我的编程之旅:技术演进与自我成长的纪录 转眼间,2023年已经悄然走到了尾声。这一年,对我来说既是挑战也是机遇的一年。我的编程之旅如同坐上了一辆高速前进的列车,从新技术的学习探索到项目实战的沉浸经历,再到…...
好用免费的WAF---如何安装雷池社区版
什么是雷池 雷池(SafeLine)是长亭科技耗时近 10 年倾情打造的 WAF,核心检测能力由智能语义分析算法驱动。 Slogan: 不让黑客越雷池半步。 什么是 WAF WAF 是 Web Application Firewall 的缩写,也被称为 Web 应用防火墙。 …...
看似 bug 又非 bug 的一个 bug
最近的一个项目中,对于 CSS 的一些属性一些选择符可以大胆使用,然后很意外得撞上一个 iOS 中 Safari 的一个解析问题。 <Component style{{height: "calc(100vh - 46px)"}}>一个组件</Component> 这样的一段代码很简单ÿ…...
mysql常见问题
批量导入SQL 数据库结构 数据时,如果数据是批量插入的话会报错:2006 - MySQL server has gone away。 解决办法:找到你的 mysql 目录下的 my.ini 配置文件,加入以下代码 max_allowed_packet500M wait_timeout288000 interactiv…...
QT上位机开发(串口界面设计)
【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing 163.com】 如果上位机要和嵌入式设备进行打交道的话,那么串口可能就是我们遇到的第一个硬件设备。串口的物理接线很简单,基本上就是收…...
k8s之pod
1、pod:k8s中最小的资源管理组件,最小化运行容器化应用的资源管理对象 (1)pod是一个抽象的概念,可以理解为一个或者多个容器化应用的集合 (2)一个pod中运行一个容器是最常用的方式 ÿ…...
第二百四十三回 再分享一个Json工具
文章目录 1. 概念介绍2. 分析与比较2.1 分析问题2.2 比较差异 3. 使用方法4. 内容总结 我们在上一章回中介绍了"分享三个使用TextField的细节"相关的内容,本章回中将再 分享一个Json插件.闲话休提,让我们一起Talk Flutter吧。 1. 概念介绍 我…...
electron自定义菜单
创建menu.js const { app, Menu } require("electron"); const createMenu () > {const menu [{label: "菜单",submenu: [{label: "新增",click: () > {},}, ],},{label: "关于",submenu: [{label: "新增",click:…...
变量和函数提升(js的问题)
• js解释执行 • 变量和函数提升 变量声明提前,函数声明提前 • 变量声明提前:值停留在本地 • 函数声明提前:整个函数体提前 如果是var赋值声明的函数,变量提前,函数体停留在本地 1、变量提…...
Excel 插件:ASAP Utilities Crack
ASAP Utilities是一款功能强大的 Excel 插件,填补了 Excel 的空白。在过去的 20 年里,我们的加载项已经发展成为世界上最受欢迎的 Microsoft Excel 加载项之一。 ASAP Utilities 中的功能数量(300 多个)可能看起来有点令人眼花缭乱…...
hyperf 十九 数据库 二 模型
教程:Hyperf 一、命令行 symfony/console-CSDN博客 hypery 十一、命令行-CSDN博客 hyperf console 执行-CSDN博客 根据之前应该能了解到命令行的基本实现,和hyperf中命令行的定义。 1.1 命令初始化 hyperf.php中系统初始化中通过ApplicationFacto…...
使用python快速开发与PDF文档对话的Gemini聊天机器人
检索增强生成(Retrieval-augmented generation,RAG)使得我们可以让大型语言模型(LLMs)访问外部知识库数据(如pdf,word、text等),从而让人们可以更加方便的通过LLM来学习外部数据的知识。今天我们将利用之前学习到的RAG方法,谷歌Gemini模型和l…...
Spring Cloud Gateway集成Knife4j
1、前提 网关路由能够正常工作。 案例 基于 Spring Cloud Gateway Nacos 实现动态路由拓展的参考地址:Spring Cloud Gateway Nacos 实现动态路由 详细官网案例:https://doc.xiaominfo.com/docs/middleware-sources/spring-cloud-gateway/spring-gatewa…...
Hive10_窗口函数
窗口函数(开窗函数) 1 相关函数说明 普通的聚合函数聚合的行集是组,开窗函数聚合的行集是窗口。因此,普通的聚合函数每组(Group by)只返回一个值,而开窗函数则可为窗口中的每行都返回一个值。简单理解,就是对查询的结果多出一列…...
ipvsadm命令详解
ipvsadm命令详解 大家好,我是免费搭建查券返利机器人赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿!今天我们将深入探讨一个在Linux系统网络管理中极具威力的命令——ipvsadm,通过详细解析…...
zabbix通过自动发现-配置监控项、触发器(小白教程)
自动发现配置参考链接(不小白,不友好) zabbix-get介绍 1配置 zabbix server:版本7(不影响),IP地址:192.168.0.60zabbix agent:版本agent1(不影响)ÿ…...
Dockerfile文件介绍
0 Preface/Foreword 0.1 Docker docker用来自制镜像。 1 Introduction 1.1 Dockerfile Dockerfile是用于定义Docker镜像的构建过程,它包含一系列的指令用于安装 软件包、配置环境等操作。 Dockerfile文件的格式如下: FROM base_image RUN apt-get up…...
【PHP】函数array_reduce()使用场景
目录 1.计算数组中所有元素的和 2.计算数组中所有元素的乘积 3.将多个字符串连接在一起 4.对数组中的元素进行逻辑计算 5.取出第一个满足条件的数组,筛选有用数组 6.array_reduce()函数的基本语法: array_reduce 函数通常用于对数组中的元素进行累…...
软件测试基础理论学习-软件测试方法论
软件测试方法论 软件测试的方法应该建立在不同的软件测试类型上,不同的测试类型会存在不同的方法。本文以软件测试中常见的黑盒测试为例,简述常见软件测试方法。 黑盒测试用例设计方法包括等价类划分法、边界值分析法、因果图法、判定表驱动法、正交试…...
Unity 关于点击不同物品移动并触发不同事件
关于点击不同物品触发不同事件 可以实现在界面中点击不同的物体,移动到物品附近位置,然后触发对应的事件。 首先建立一个公共管理的类: public class InteractionObject : MonoBehaviour {private NavMeshAgent PlayerAgent;private bool …...
c++IO库详细介绍
文章目录 前言c IO 类简介1. iostream库iostream 类标准IO对象 2. fstream库fstream 类 3. stringstream库stringstream 类 格式化和控制错误处理 IO对象无拷贝或赋值IO条件状态主要的状态标志检查流状态控制流状态示例 管理输出缓冲主要操作示例 文件输入输出使用文件流对象示…...
海外静态IP和动态IP有什么区别?推荐哪种?
什么是静态ip、动态ip,二者有什么区别?哪种好?关于这个问题,不难发现,在知道、知乎上面的解释有很多,但据小编的发现,这些回答都是关于静态ip和动态ip的专业术语解释,普通非专业人事…...
五莲网站建设报价/请输入搜索关键词
一、编程语言分类:1、按特性分类:机器语言:编程入门非常困难,执行速度最快。汇编语言:编程相对机器语言简单(采用助记符编程),针对某种具体的CPU。高级语言:贴近生活中的…...
北京企业网站建设价格/阿里云搜索
通过上面pt-table-checksums找到了这些不一致的数据表(https://blog.51cto.com/li02yu/2340403),如何同步数据呢?即如何修复MySQL主从不一致的数据,让他们保持一致性呢?利用另外一个工具 pt-table-sync。使…...
网站美工培训课程/网络优化公司哪家好
作者 | Raini 出品 | 图特摩斯(北京)科技有限公司 AbutionGraph是什么? AbutionGraph是一种能对历史和实时数据提供亚秒级别查询的多维图数据存储与分析平台。 AbutionGraph支持低延时的数据摄取,灵活的数据探索分析,高性能的…...
预约网站怎么做/广东省广州市佛山市
以前看漫画的时候如果有对话内容,一般会有一个边框,然后带着一个三角从说话人的身上引出。类似下图这样: 应该有很多方法来实现,这里提供的办法就是创造一个边框,然后用两个三角覆盖。效果如下: 为了方便理…...
wordpress在centos/推广普通话海报
伺服是由3个反馈系统构成:位置环、速度环、电流环,越是内侧的环,越需要提高其响应性,不遵守该原则,则会产生偏差和震动。由于电流环是最内侧的环,以确保了其充分的响应性,所以我们只需要调整位置…...
网站建设行业资讯/腾讯推广一次广告多少钱
转自:http://blog.csdn.net/tanyujing/article/details/8717575 钢笔测试 能在不同的纸上写吗?能在墙上写吗?笔尖朝上,倒着拿还能写出字吗? 能在不同的环境下写吗?水里?沙漠?低温&a…...