1、Promise

基本介绍及用法咱就不唠了,详见 https://segmentfault.com/a/1190000023334712传送门1
唠一唠Promise的特点
两个特点
Promise对象的状态不受外界影响
> Promise对象代表一个异步操作,共三个阶段,pending(进行中)、fulfilled(已成功)、rejected(已失败)。也就是只有异步操作的结果才可以决定当前是哪一种状态,其他操作都无法改变状态,所以才叫Promise(承诺)。状态一旦改变,就不会再变,任何时候都可以得到这个结果
那么看例子:
let p2 = new Promise((resolve, reject) => { throw new Error('报错了'); }) .then(result => result) .catch(e => e); // log undefined
结果是undefined,此处虽然进行了throw err,但是没有在catch进行具体的操作,而只是e=>e,还是返回一个Promise实例。
再看:
let p2 = new Promise((resolve, reject) => { throw new Error('报错了'); }) .then(result => result) .catch(e => e) .then(() => {console.log('111')}) .catch(() => {console.log('222')}) .then(() => {console.log('333')}) .catch(() => {console.log('444')}); // log 111 333
也就是catch没有调用Promise.reject()改变状态的话,Promise会一直默认走.then而不会走.catch。
这也是Promise中的重头戏,我们在用Promise的时候可能会发现,当then函数中return了一个值,我们可以继续then下去,不过是什么值,都能在下一个then中获取,还有,当我们不在then中放入参数,例:promise.then().then(),那么其后面的then依旧可以得到之前then返回的值。
为什么呢,传送门2
首先我们要注意的一点是,then有返回值,then了之后还能在then,那就说明之前的then返回的必然是个Promise。
相信看完 传送门2 就不需要我多比比了,记得如果没改变状态会一直默认走then而不会走catch就行了
看例子:
let p2 = new Promise((resolve, reject) => { throw new Error('报错了'); }).then(result => result) .catch(e => {console.log(e);return Promise.reject('2')}) .then(() => {console.log('111')}) .catch(() => {console.log('222')}) .then(() => {console.log('333')}) .catch(() => {console.log('444')}); //log Error: 报错了 at:2:9 at new Promise () at:1:10 222 333
结果来看,可知进行Promise.reject()后,Promise实例状态从pending变为rejected了,所以才会走catch,但是走了catch之后还是可以继续.then,但此时Promise实例的状态已经定格为rejected了,无法再改变了。
先这样吧,后续补充,欢迎指正

2、实现Promise.all

注意两点:
1、先判断参数是否iterator;
2、非promise实例进行Promise.resolve()
3、如果全部成功,状态变为resolved,返回值将组成一个数组传给回调
4、只要有一个失败,状态就变为rejected,返回值将直接传递给回调,且返回值也是新的Promise对象
第一遍:
// 第一遍 function Promiseall(promises) { // 先判断参数是否可遍历,也就是有无iterator接口 const iterator = Symbol.iterator if(!promises[iterator]) return return new Promise((resolve, reject) => { const resolvearr = [] const rejectarr = [] for(let i of promises) { // 如果不是promise实例,则使用Promsie.resolve()函数将其转换为promise实例 if(!(i instanceof Promise)) { i = Promise.resolve(i) } i.then(res => { // 成功,将返回放进resolvearr数组 resolvearr.push(res) }).catch( err => { // 报错,将错误放进rejectarr数组 rejectarr.push(err) }) } setTimeout(() => { // 判断rejectarr长度 // 如果为0, 则返回resolve(resolvearr); // 如果不为0,则表示有一个实例报错,所以将报错的那一个示例返回 return rejectarr.length === 0?resolve(resolvearr) : reject(rejectarr[0]) }) }) } // test const p1 = new Promise(res => res(1)) const p2 = new Promise((res,rej) => rej(2)) const p3 = new Promise((res,rej) => rej(3)) const p4 = '4' const result = Promiseall([p1,p2,p3,p4]) .then(res => {console.log(res)}) .catch(rej => {console.log(rej)}) console.log(result)
几个问题:
1、all为Promise的静态函数
2、reject数组duck不必
3、使用push将结果放入数组的话不能保证返回值是按顺序的
4、长度判断应该放在.then里,相对核心的一部分
5、注意到.catch里return的是reject(err)而不是直接return err,因为要返回Promise实例
以下为针对以上问题改正后的版本,欢迎指正:
// 别直接用all,有可能会被Promise自身的all覆盖 Promise.alll=function(promises){ // 1、先判断是否iterator;2、非promise实例进行Promise.resolve() constiterator=Symbol.iterator if(!promises[iterator])return letcount=0 // 返回的是一个Promise实例,所以没有.then或.catch returnnewPromise((resolve,reject)=>{ // 定义数组接收每一个Promise实例的返回 constresolveArr=[] for(leti=0;i