nodejs - Promise 用法与面试题分析

这是新年的第一篇技术文,加油干。这是一篇整合型文章,多出参考了其他文章,文末给出出处。
是的,和标题一样,我这边是面向 nodejs 后端,而不是面向前端写的,所以会以后端的想法去写。

什么是 Promise

Promise 库是用来处理异步操作的,由于好用且强大,ES6 原生提供了 Promise。
Promise 有三种状态:

  1. pending(进行中)
  2. fulfilled(已成功)
  3. rejected(已失败)
    nodejs - Promise 用法与面试题分析_第1张图片

如图,Promise 可以从 pending 转为 fulfilled ,也可以从 pending 转为 rejected 。但是一但状态转变之后,Promise 就会记住运行结果,再次调用时会直接获取结果。还有一个要知道的是,当 Promise 在运行的时候,是无法中断执行的。
但是在实际编程当中,会用 resolved 代指 fulfilled 。

Promise 用法

const myPromise = new Promise(function (resolve, reject) {
    if (true) {//异步操作成功
        resolve("success");
    } else {
        reject("there is some error!");
    }
})

myPromise.then(function (value) {
    console.log("111");
    console.log(value);
}, function (error) {
    console.log("222");
    console.log(error)
});
//运行结果:
//111
//success

Promise 的构造函数接受两个由 JavaScript 引擎提供的回调函数,分别是:resolve,reject。resolve 是操作成功时的回调函数,与此同时 Promise 的状态由 pending 转化为 resolved。reject 是操作失败的回到函数,与此同时 Promise 的状态由 pending 转化为 reject。
Promise 实例生成之后,使用 then 方法继续操作。then 方法接受两个回调函数作为参数。分别对应构造 Promise 的时候的两个回调函数(resolv,reject)

Promise.then() 与 Promise.catch()
Promise.catch() 相当于 Promise.then(null, rejection),用于捕获错误的回调函数。

const myPromiseCatch = new Promise(function (resolve, reject) {
    if (true) {
        reject(new Error("there are some errors!!!"))
    } else {
        resolve("asdf");
    }
});

myPromiseCatch.then(function (value) {
    console.log(value)
}).catch(function (error) {
    console.log(error)
})
//运行结果:there are some errors!!!

Promise.all
将多个 promise 实例合并成一个。
const p = Promise.all([p1, p2, p3]);
p的状态由p1、p2、p3决定:

(1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。

(2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。

// 生成一个Promise对象的数组
const promises = [2, 3, 5, 7, 11, 13].map(function (id) {
  return getJSON('/post/' + id + ".json");
});

Promise.all(promises).then(function (posts) {
  // ...
}).catch(function(reason){
  // ...
});

Marcro task 与 Micro task

为什么要写这个呢?是为了接下来的面试题而做铺垫。
关于这个,我搜索了挺多文章,好像都没有解释得通的。还好,最后搜到了一篇比较满意的(见文末)。
nodejs 中的 EventLoop 有任务队列 EventQueue(TaskQueue)
Task 分为两大类:Marcro task 与 Micro task;两者的执行顺序:每执行完成一个 Macro Task 就要清空当前所有的 Micro Task。接下来是一些分类:

Macrotask

  • setImmediate
  • setTimeout
  • setInterval

Microtask

  • process.nextTick
  • Promise
  • Object.observe
  • MutaionObserver

(图作者@BusyRich)。
这里写图片描述

再进一步划分,从微观实现的角度讲, 引擎都会有三个 Task Queue:

  • Macro Task Queue —–> 处理 Micro Task Queue
  • Micro Task Queue ——> 处理 Promise 等 microtask
  • Tick Task Queue ——-> 处理 process.nextTick

那么在一个事件循环中,其伪代码展示如下:

for (macroTask of macroTaskQueue) {
    // 1. Handle current MACRO-TASK
    handleMacroTask();
    // 2. Handle all NEXT-TICK
    for (nextTick of nextTickQueue) {
        handleNextTick(nextTick);
    }
    // 3. Handle all MICRO-TASK
    for (microTask of microTaskQueue) {
        handleMicroTask(microTask);
    }
    }

Promise 面试题

这个题是大佬 nswbmw 的,我觉得还是挺不错的,有些题我们能够直接看注释看懂。而有些题则需要涉及到上面的 Marcro task 与 Micro task 的知识。
Promise 必知必会(十道题)

Macrotask 与 Microtask 核心概念
ECMAScript 6 入门

你可能感兴趣的:(nodejs)