Promise的面试题考点

面试题考点

Promise的基本概念

Promise的面试题考点_第1张图片

链式调用规则

Promise的面试题考点_第2张图片

Promise的面试题考点_第3张图片

  1. then方法必定会返回一个新的Promise

    可理解为后续处理也是一个任务

  2. 新任务的状态取决于后续处理:

    • 若没有相关的后续处理,新任务的状态和前任务一致,数据为前任务的数据

    • 若有后续处理但还未执行,新任务挂起。

    • 若后续处理执行了,则根据后续处理的情况确定新任务的状态

      • 后续处理执行无错,新任务的状态为完成,数据为后续处理的返回值
      • 后续处理执行有错,新任务的状态为失败,数据为异常对象
      • 后续执行后返回的是一个任务对象,新任务的状态和数据与该任务对象一致

Promise的静态方法

方法名 含义
Promise.resolve(data) 直接返回一个完成状态的任务
Promise.reject(reason) 直接返回一个拒绝状态的任务
Promise.all(任务数组) 返回一个任务
任务数组全部成功则成功
任何一个失败则失败
Promise.any(任务数组) 返回一个任务
任务数组任一成功则成功
任务全部失败则失败
Promise.allSettled(任务数组) 返回一个任务
任务数组全部已决则成功
该任务不会失败
Promise.race(任务数组) 返回一个任务
任务数组任一已决则已决,状态和其一致

async和await

有了Promise,异步任务就有了一种统一的处理方式

有了统一的处理方式,ES官方就可以对其进一步优化

ES7推出了两个关键字asyncawait,用于更加优雅的表达Promise

async

async关键字用于修饰函数,被它修饰的函数,一定返回Promise

async function method1(){
  return 1; // 该函数的返回值是Promise完成后的数据
}

method1(); // Promise { 1 }

async function method2(){
  return Promise.resolve(1); // 若返回的是Promise,则method得到的Promise状态和其一致
}

method2(); // Promise { 1 }

async function method3(){
  throw new Error(1); // 若执行过程报错,则任务是rejected
}

method3(); // Promise {  Error(1) }

await

await关键字表示等待某个Promise完成,它必须用于async函数中

async function method(){
  const n = await Promise.resolve(1);
  console.log(n); // 1
}

// 上面的函数等同于
function method(){
  return new Promise((resolve, reject)=>{
    Promise.resolve(1).then(n=>{
      console.log(n);
      resolve(1)
    })
  })
}

await也可以等待其他数据

async function method(){
  const n = await 1; // 等同于 await Promise.resolve(1)
}

如果需要针对失败的任务进行处理,可以使用try-catch语法

async function method(){
  try{
    const n = await Promise.reject(123); // 这句代码将抛出异常
    console.log('成功', n)
  }
  catch(err){
    console.log('失败', err)
  }
}

method(); // 输出: 失败 123

事件循环

根据目前所学,进入事件队列的函数有以下几种:

  • setTimeout的回调,宏任务(macro task)
  • setInterval的回调,宏任务(macro task)
  • Promise的then函数回调,微任务(micro task)
  • requestAnimationFrame的回调,宏任务(macro task)
  • 事件处理函数,宏任务(macro task)

面试题

  1. 下面代码的输出结果是什么

    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 对象的状态变为已解决(fulfilled)。然后输出2。
    然后,调用 promise.then() 方法注册一个回调函数,该回调函数会在 Promise 对象状态变为已解决时执行。此时,Promise 对象的状态已经是已解决,所以回调函数会立即执行,输出3。
    最后,输出4。
    总结:Promise 对象的执行是异步的,即使 Promise 对象的状态立即变为已解决,注册的回调函数也会在下一个事件循环中执行。因此,输出的顺序是1243
  2. 下面代码的输出结果是什么

    const promise = new Promise((resolve, reject) => {
        console.log(1); 
        setTimeout(()=>{
          console.log(2)
          resolve(); 
          console.log(3);
        })
    })
    
    promise.then(() => {
        console.log(4);
    })
    
    console.log(5);
    // 1 5 2 3 4
    解释如下:
    
    首先,创建了一个 Promise 对象,并传入一个执行器函数作为参数。执行器函数立即执行,输出1。
    接着,执行器函数中调用 setTimeout() 方法,将其中的代码放入宏任务队列中,并设置一个延迟时间。此时,setTimeout() 方法中的代码不会立即执行,而是在延迟时间结束后才执行。
    然后,继续执行后续代码,输出5在延迟时间结束后,setTimeout() 方法中的代码开始执行。首先输出2,表示延迟时间结束后的第一个执行的任务。
    然后,调用 resolve() 方法,表示 Promise 对象的状态变为已解决(fulfilled)。
    接着,输出3。
    最后,注册在 promise.then() 方法中的回调函数会在 Promise 对象状态变为已解决时执行。此时,Promise 对象的状态已经是已解决,所以回调函数会立即执行,输出4。
    总结:由于 setTimeout() 方法中的代码被放入宏任务队列中,所以会在后续代码执行完毕后才执行。因此,输出的顺序是15234
  3. 下面代码的输出结果是什么

    const promise1 = new Promise((resolve, reject) => {
    	setTimeout(() => {
        resolve()
      }, 1000)
    })
    const promise2 = promise1.catch(() => {
      return 2;
    })
    
    console.log('promise1', promise1) 
    console.log('promise2', promise2) 
    
    setTimeout(() => {
      console.log('promise1', promise1) 
      console.log('promise2', promise2) 
    }, 2000)
    // promise1 Promise {} promise2 Promise {}
    // promise1 Promise {} promise2 Promise {}
    解释如下:
    
    首先,创建了一个 Promise 对象 promise1,并在其执行器函数中使用 setTimeout() 方法设置了一个延迟时间为1秒的定时任务。在定时任务执行后,调用 resolve() 方法,将 promise1 的状态设置为已解决(fulfilled)。
    接着,创建了一个新的 Promise 对象 promise2,并使用 promise1.catch() 方法注册了一个错误处理回调函数。由于 promise1 的状态是已解决,所以错误处理回调函数不会执行。promise2 的状态与 promise1 相同。
    然后,输出 promise1 和 promise2 的值。由于 promise1 和 promise2 的状态都是待定(pending),所以输出为 Promise {<pending>}。
    在2秒后,执行第二个 setTimeout() 方法中的代码。此时,promise1 的状态已经是已解决,所以输出 promise1 的值为 Promise {<resolved>}。由于 promise2 是通过 promise1.catch() 方法创建的,并且没有发生错误,所以 promise2 的状态也是已解决,输出 promise2 的值为 Promise {<resolved>}。
    总结:在定时任务执行前,promise1 和 promise2 的状态都是待定(pending)。在定时任务执行后,promise1 的状态变为已解决(fulfilled),promise2 的状态与 promise1 相同。
    
  4. 下面代码的输出结果是什么

    async function m(){
      console.log(0)
      const n = await 1;
      console.log(n);
    }
    //等价于
    function m(){
        console.log(0)
    	return Promise.resolve(1).then((n)=>{
            console.log(n)
        })
    }
    
    m();
    console.log(2);
    // 0 2 1
    现在让我们逐步解释每个输出:
    
    首先,代码开始执行,调用了 m() 函数,即 m();。这个函数调用会立即开始执行,但需要注意的是,m() 函数内部包含了一个 await 表达式 const n = await 1;,它会暂停函数的执行,直到 await 后面的表达式解决为 Promise,并等待 Promise 完成。在这里,await 1; 表示等待一个解决为 1 的 Promise,由于这是一个立即解决的 Promise,所以不会有延迟,函数会继续执行。然后,const n = 1; 将 n 设置为 1,但在这个点上,console.log(n); 还没有执行。
    
    接下来,console.log(2); 输出 2,因为此时程序继续执行,没有等待 m() 函数内部的异步操作完成。
    
    最后,console.log(n); 输出 1,因为在 m() 函数内部,n 的值已经被设置为 1
  5. 下面代码的输出结果是什么

    async function m(){
      console.log(0)
      const n = await 1;
      console.log(n);
    }
    
    (async ()=>{
      await m();
      console.log(2);
    })();
    
    console.log(3);
    // 0 3 1 2
    现在让我们逐步解释每个输出:
    
    首先,代码开始执行,遇到了最外层的 console.log(3);。这行代码会立即执行,输出 3接下来,进入立即执行的自执行异步函数 (async () => { ... })();,它会立即开始执行。在函数内部,遇到 await m(); 这行代码,它调用了 m() 函数。然而,需要注意的是,m() 函数内部包含了一个 await 表达式 const n = await 1;,它会暂停函数的执行,直到 await 后面的表达式解决为 Promise,并等待 Promise 完成。在这里,await 1; 表示等待一个解决为 1 的 Promise,由于这是一个立即解决的 Promise,所以不会有延迟,函数会继续执行。然后,const n = 1; 将 n 设置为 1,并继续执行函数内部。
    
    console.log(n); 输出 1,因为此时 n 的值已经被设置为 1函数执行完毕后,继续执行 (async () => { ... })(); 后面的 console.log(2);,输出 2
  6. 下面代码的输出结果是什么

    async function m1(){
      return 1;
    }
    
    async function m2(){
      const n = await m1();
      console.log(n)
      return 2;
    }
    
    async function m3(){
      const n = m2();
      console.log(n);
      return 3;
    }
    
    m3().then(n=>{
      console.log(n);
    });
    
    m3();
    
    console.log(4);
    // 4 1 3 1
    

    Promise的面试题考点_第4张图片

  7. 下面代码的输出结果是什么

    Promise.resolve(1)	
      .then(2)// then里传的不是函数,就相当于可以把这个then给删了
      .then(Promise.resolve(3))// then里传的不是函数,就相当于可以把这个then给删了
      .then(console.log)
    //等价于
    Promise.resolve(1)	
      .then(console.log)
    // 1
    
  8. 下面代码的输出结果是什么

    var a;
    var b = new Promise((resolve, reject) => {
      console.log('promise1');
      setTimeout(()=>{
        resolve();
      }, 1000);
    }).then(() => {
      console.log('promise2');
    }).then(() => {
      console.log('promise3');
    }).then(() => {
      console.log('promise4');
    });
    
    a = new Promise(async (resolve, reject) => {
      console.log(a);
      await b;
      console.log(a);
      console.log('after1');
      await a
      resolve(true);
      console.log('after2');
    });
    
    console.log('end');
    

    Promise的面试题考点_第5张图片

    Promise的面试题考点_第6张图片

  9. 下面代码的输出结果是什么

    async function async1() {
        console.log('async1 start');
        await async2();
        console.log('async1 end');
    }
    async function async2() {
    	console.log('async2');
    }
    
    console.log('script start');
    
    setTimeout(function() {
        console.log('setTimeout');
    }, 0)
    
    async1();
    
    new Promise(function(resolve) {
        console.log('promise1');
        resolve();
    }).then(function() {
        console.log('promise2');
    });
    console.log('script end');
    // script start
    // async1 start
    // async2
    // promise1
    // script end
    // async1 end
    // promise2
    // setTimeout
    

你可能感兴趣的:(前端,笔记,javascript)