乐趣区

关于es6:Promise的一些理解Promiseall实现

1、Promise

根本介绍及用法咱就不唠了,详见 传送门 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 <anonymous>:2:9
  at new Promise (<anonymous>)
  at <anonymous>: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()
    const iterator = Symbol.iterator
    if (!promises[iterator]) return
    let count = 0
    // 返回的是一个 Promise 实例,所以没有.then 或.catch
    return new Promise((resolve, reject) => {
        // 定义数组接管每一个 Promise 实例的返回
        const resolveArr = []
        for (let i = 0; i < promises.length; i++) {// 判断参数是否为 Promise 实例,不是则应用 Promise.resolve()将其转换为实例
            if (!(promises[i] instanceof Promise)) {promises[i] = Promise.resolve(promises[i])
            }
            promises[i].then(res => {
                // 不应用 push,是因为要保障按程序输入
                resolveArr[i] = res
                count++
                // 长度判断? 外围?判断 arr 与参数长度
                if (count === promises.length) {return resolve(resolveArr)
                }
            }).catch(err => {
                // 留神返回的是 Promise 实例,所以要调用 reject 办法,而不是间接 return err
                return reject(err)
            })
        }
    })
}

// test
// test
let p1 = new Promise(res => res(1))
let p2 = new Promise((res,rej) => res(2))
let p3 = new Promise((res,rej) => res(3))
let p4 = '4'
Promise.alll([p1,p2,p3,p4])
       .then(res => {console.log(res)})
       .catch(rej => {console.log(rej)})

最初鸣谢 cvSoldiel 的指导

退出移动版