欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Promise最全解!

程序员文章站 2022-07-03 10:34:51
...

一. Promise特性类问题

1.说说你理解的Promise

(1)代理对象: Promise 对象是一个代理对象。Promise对象接受传入的 executor(执行器)作为入参,将异步任务的成功和失败分别绑定到对应的处理方法上去。
(2)Promise对象的两个特点:
**三个状态:**一个 Promise 实例有三种状态:
• pending 状态,表示进行中。这是 Promise 实例创建后的一个初始态;
• fulfilled 状态,表示异步任务成功完成。这是在执行器中调用 resolve 后,达成的状态;
• rejected 状态,表示操作失败、被拒绝。这是在执行器中调用 reject后,达成的状态;
状态切换机制: Promise实例的状态是可以改变的,但它只允许被改变一次。当我们的实例状态从 pending 切换为 rejected 后,就无法再扭转为 fulfilled,反之同理。当 Promise 的状态为fulfilled 时,会触发其对应的 then 方法入参里的 onfulfilled 函数;当 Promise 的状态为 rejected 时,会触发其对应的 catch 方法入参里的 onrejected 函数。

2. Promise的出现是为了解决什么问题

为了解决大量异步链式调用出现的回调地狱问题。

3. Promise 常见方法有哪些?各自是干嘛的?

1.then(): 分别指定resolved状态和rejected状态的回调函数
第一参数: 状态变为resolved时调用
第二参数: 状态变为rejected时调用(可选))

2.catch(): 指定发生错误时的回调函数

3.Promise.all(iterable) ,返回一个新的 promise 对象,该 promise 对象在 所有的 promise 对象都成功的时候才会触发成功, 一旦有任何一个 promise 对象失败则立即触发该 promise 对象的失败。该 promise 也会用子 promise 的成功返回值或失败详情作为参数调用 promise 绑定的相应处理函数,成功的返回值为所有的promise对象的成功返回值组成的数组。

Promise.all 里的任务列表是按照顺序一个一个发起的。
但是它们是异步的,互相之间并不阻塞,每个任务完成时机是不确定的,尽管如此,所有任务结束之后,它们的结果仍然是按顺序地映射到resultList里,这样就能和Promise.all里的任务列表一一对应起来。

var p1 = Promise.resolve('1号选手');
var p2 = '2号选手';
var p3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, "3号选手");
}); 
Promise.all([p1, p2, p3]).then(values => { 
  console.log(values); //  ["1号选手", "2号选手", "3号选手"]
});
  1. Promise.race(iterable),这个方法顾名思义,就是取出响应最快的那个请求。返回一个promise对象,该promise对象在任意一个子 promise 被成功或失败后,会立即被触发成功或者失败。该 promise 也会用子 promise 的成功返回值或失败详情作为参数调用 promise 绑定的相应处理函数
var p1 = new Promise(function(resolve, reject) { 
    setTimeout(resolve, 100, "1号选手"); 
});
var p2 = new Promise(function(resolve, reject) { 
    setTimeout(resolve, 50, "2号选手"); 
});

// 这里因为 2 号选手返回得更早,所以返回值以 2号选手为准
Promise.race([p1, p2]).then(function(value) {
  console.log(value); //  "2号选手"
});

5.Promise.resolve(value):它返回一个 Promise 对象,传入的参数分为以下两种:
传入的是promise对象,返回的Promise对象的最终状态由传入的promise对象的状态决定
传入的是一个值,返回的 Promise 对象状态为 fulfilled,同时这里的 value 会作为 then 方法中指定的 onfulfilled 的入参。
传入的是Thenable对象(指具有then方法的对象),Promise.resolve方法会将这个对象转为Promise对象,然后立即执行thenable对象的then方法

6.Promise.reject(reason): 返回一个状态为失败的Promise对象,并将reason传递给对应的处理方法。

4.promise的缺点

  • 可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数
  • Promise对象提供统一的的接口,使得控制异步操作更加容易

5.Promise缺点:

  • 无法取消,一旦新建它就会立即执行,无法中途取消;
  • 如果不设置回调函数,Promise内部抛出的错误,不会反映到外部;
  • 当处于pending状态时,无法得知目前进展到哪一个阶段(刚开始还是即将完成)

二. 面试代码类问题

1.Promise 中的处理函数是异步任务,then 方法中传入的任务是一个异步任务。

const promise = new Promise((resolve, reject) => {
    console.log(1);
    resolve();
    console.log(2);
});

promise.then(() => {
    console.log(3);
});

console.log(4);
// 1 2 4 3

生成Promise实例后,先打印1,resolve() 这个调用,作用是将 Promise 的状态从 pending 置为 fulfilled,这个新状态会让 Promise 知道“我的 then 方法中那个任务可以执行了”——注意是”可以执行了“,而不是说”立刻就会执行“。毕竟作为一个异步任务,它的基本修养就是要等同步代码执行完之后再执行。所以说数字 3 的输出排在最后。

  1. Promise 对象的状态只能被改变一次
const promise = new Promise((resolve, reject) => {
  resolve('第 1 次 resolve')
  console.log('resolve后的普通逻辑')
  reject('error')
  resolve('第 2 次 resolve')
})
 
promise
.then((res) => {
  console.log('then: ', res)
})
.catch((err) => {
  console.log('catch: ', err)
})
// resolve后的普通逻辑
// then:  第 1 次 resolve

3.Promise 值穿透问题

Promise.resolve(1)
  .then(Promise.resolve(2))   // then方法不识别
  .then(3)    // then方法不识别
  .then()     // then方法不识别
  .then(console.log)   // then方法终于识别
  // 1

then参数期望是函数,onFulfilled(成功态的处理函数)和 onRejected(失败态的处理函数)。传入非函数则会发生值穿透。值传透可以理解为,当传入then的不是函数的时候,这个then是无效的。

  1. 一个promise指定多个成功/失败回调函数, 都会调用吗?
    答:当promise改变为对应状态时都会调用
let p = new Promise((resolve, reject) => {
    resolve('Promise状态会被标记为resolved')
   // reject('Promise状态会被标记为rejected')
   // throw new Error('Promise状态会被标记为rejected')
});
p.then(
    value => {
        console.log('value1', value) // value1 Promise状态会被标记为resolved
    },
    reason => {
        console.log('reason1', reason)
    }
).then(
    value => {
        console.log('value2', value)     // value2 undefined
    },
    reason => {
        console.log('reason2', reason)
    }
)

5.promise如何串连多个操作任务?
(1) promise的then()返回一个新的promise, 可以开成then()的链式调用
(2) 通过then的链式调用串连多个同步/异步任务

new Promise((resolve, reject) => {
    setTimeout(() => {
        console.log("执行任务1(异步)")
        resolve(1)
    }, 1000);
}).then(
    value => {
        console.log('任务1的结果: ', value)
        console.log('执行任务2(同步)')
        return 2
    }
).then(
    value => {
        console.log('任务2的结果:', value)

        return new Promise((resolve, reject) => {
            // 启动任务3(异步)
            setTimeout(() => {
                console.log('执行任务3(异步))')
                resolve(3)
            }, 1000);
        })
    }
).then(
    value => {
        console.log('任务3的结果: ', value)
    }
)


6.中断promise链
(1)当使用promise的then链式调用时, 在中间中断, 不再调用后面的回调函数
(2)办法: 在回调函数中返回一个pending状态的promise对象
return new Promise(()=>{}) // 返回一个pending的promise 中断promise链

三、Promise 底层原理考察

手写Promise