从几个前端面试题再学Promise

689 阅读4分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动

从几个前端面试题再学Promise

1. 以下代码的输出是什么?

Promise.resolve(10).then(res => {
    console.log(res)
}).catch(error => {
    console.log(error)
}).then(res => {
    console.log(res)
})

Promise.resolve(10).then(res => {
    console.log(res)
}).then(res => {
    console.log(res)
}).catch(error => {
    console.log(error)
})

Promise.reject(10).then(res => {
    console.log(res)
}).catch(error => {
    console.log(error)
}).then(res => {
    console.log(res)
})

Promise.reject(10).then(res => {
    console.log(res)
}).then(res => {
    console.log(res)
}).catch(error => {
    console.log(error)
})

一开始以为弄懂了,说完答案之后面试官都给整乐了。
面试官:老哥,你回去再好好了解一下Promise的原理。

这题的知识点包括:

  1. 因为 Promise.prototype.then 和  Promise.prototype.catch 方法返回的是 promise, 所以它们可以被链式调用。
  2. 如果针对某个状态的回调函数参数为空(null,undefined),MDN上是这么描述的。

注意:如果忽略针对某个状态的回调函数参数,或者提供非函数 (nonfunction) 参数,那么 then 方法将会丢失关于该状态的回调函数信息,但是并不会产生错误。如果调用 then 的 Promise 的状态(fulfillment 或 rejection)发生改变,但是 then 中并没有关于这种状态的回调函数,那么 then 将创建一个没有经过回调函数处理的新 Promise 对象,这个新 Promise 只是简单地接受调用这个 then 的原 Promise 的终态作为它的终态。

可以理解为 如果没有传入相应的回调函数,Promise会有默认的处理。
返回一个和原Promise终态相同的新Promise。

  1. then()的返回值和then()中传入的回调函数有关。 这里不特指接受或拒绝的回调函数,可以一起讨论。
then() 中的回调函数then 返回的 Promise
返回了一个值那么 then 返回的 Promise 将会成为接受状态,并且将返回的值作为接受状态的回调函数的参数值。
没有返回任何值那么 then 返回的 Promise 将会成为接受状态,并且该接受状态的回调函数的参数值为 undefined
抛出一个错误那么 then 返回的 Promise 将会成为拒绝状态,并且将抛出的错误作为拒绝状态的回调函数的参数值。
返回一个已经是接受状态(fulfilled)的 Promise那么 then 返回的 Promise 也会成为接受状态,并且将那个 Promise 的接受状态的回调函数的参数值作为该被返回的Promise的接受状态回调函数的参数值。
返回一个已经是拒绝状态(rejected)的 Promise那么 then 返回的 Promise 也会成为拒绝状态,并且将那个 Promise 的拒绝状态的回调函数的参数值作为该被返回的Promise的拒绝状态回调函数的参数值。
返回一个未定状态(pending)的 Promise那么 then 返回 Promise 的状态也是未定的,并且它的终态与那个 Promise 的终态相同;同时,它变为终态时调用的回调函数参数与那个 Promise 变为终态时的回调函数的参数是相同的。
  1. catch()是特殊的then()

catch()  方法返回一个Promise (en-US),并且处理拒绝的情况。它的行为与调用Promise.prototype.then(undefined, onRejected) 相同。 (事实上, calling obj.catch(onRejected) 内部calls obj.then(undefined, onRejected)).

通过以上的性质,我们可以解答刚刚的问题了

Promise.resolve(10).then(res => {
    console.log(`res00 => ${res}`)
}).catch(error => {
    console.log(`error => ${error}`)
}).then(res => {
    console.log(`res01 => ${res}`)
})

// res00 => 10
// res01 => undefined

/*

1. resolve()返回一个fulfilled状态的promise
2. 第一个then()中注册了fulfilled状态的回调函数,
   打印 res00 => 10
   因为函数没有返回值
   所以返回一个promise(fulfilled,undefined)              => 知识点3
3. catch中没有注册fulfilled状态的回调函数,
   所以返回一个promise(fulfilled,undefined)              => 知识点2
4. 第二个then()中注册了fulfilled状态的回调函数,
   打印 res01 => undefined
   因为函数没有返回值
   所以返回一个promise(fulfilled,undefined)              => 知识点3
   
*/
Promise.resolve(10).then(res => {
    console.log(`res00 => ${res}`)
}).then(res => {
    console.log(`res01 => ${res}`)
}).catch(error => {
    console.log(`error => ${error}`)
})

// res00 => 10
// res01 => undefined

/*

1. resolve()返回一个fulfilled状态的promise
2. 第一个then()中注册了fulfilled状态的回调函数,
   打印 res00 => 10
   因为函数没有返回值
   所以返回一个promise(fulfilled,undefined)              => 知识点3
3. 第二个then()中注册了fulfilled状态的回调函数,
   打印 res01 => undefined
   因为函数没有返回值
   所以返回一个promise(fulfilled,undefined)              => 知识点3
4. catch中没有注册fulfilled状态的回调函数,
   所以返回一个promise(fulfilled,undefined)              => 知识点2
*/
Promise.reject(10).then(res => {
    console.log(`res00 => ${res}`)
}).catch(error => {
    console.log(`error => ${error}`)
}).then(res => {
    console.log(`res01 => ${res}`)
})

// error => 10
// res01 => undefined

/*

1. reject()返回一个rejected状态的promise
2. 第一个then()中注册了fulfilled状态的回调函数,
   没有注册rejected状态的回调函数,
   所以返回一个promise(rejected,10)                      => 知识点2
3. catch中注册了rejected状态的回调函数,
   打印 error => 10
   因为函数没有返回值
   所以返回一个promise(fulfilled,undefined)              => 知识点3
4. 第二个then()中注册了fulfilled状态的回调函数,
   打印 res01 => undefined
   因为函数没有返回值
   所以返回一个promise(fulfilled,undefined)              => 知识点3
   
*/
Promise.reject(10).then(res => {
    console.log(`res00 => ${res}`)
}).then(res => {
    console.log(`res01 => ${res}`)
}).catch(error => {
    console.log(`error => ${error}`)
})

// error => 10

/*

1. reject()返回一个rejected状态的promise
2. 第一个then()中注册了fulfilled状态的回调函数,
   没有注册rejected状态的回调函数,
   所以返回一个promise(rejected,10)                      => 知识点2
3. 第二个then()中注册了fulfilled状态的回调函数,
   没有注册rejected状态的回调函数,
   所以返回一个promise(rejected,10)                      => 知识点2
3. catch中注册了rejected状态的回调函数,
   打印 error => 10
   因为函数没有返回值
   所以返回一个promise(fulfilled,undefined)              => 知识点3
   
*/

2. 同时发出10个请求,全部成功之后做一些处理

这一题可以用 Promise.all

Promise.all([p1,p2,p3])

3. 有一个请求,如果5s内有响应就返回响应,5s内没有响应就返回超时。

这一题可以用 Promise.race()


function func(p1, ms = 5000){
    let p = new Promise((resolve,reject)=>{
        let t = setTimeout(()=>{
            resolve()
        },ms)
    })

    return Promise.race(p1,p)
}