Promise 保教不会

Promise 是什么,为什么会产生 promise(即讲明相对于以往有什么优势),缺点是什么,更好的方案

  • 是什么?ES6 出的 异步编程的一种解决方案,是为了解决回调地狱问题,使代码可读性更高,便于维护

Promise 具体语法是怎么样,有哪些特征

  • 语法
    • 三种状态 pending 、resolve、reject。状态一旦变更无法修改
    • Promise 传入 executor,有 resolve 和 reject,
  • 特征
    • then、catch、Promise.all、Promise.race
      • then
        • 获得异步变更后的状态
        • 返回的也是一个 promise 对象
      • catch
        • 捕获错误,如果你在 then 中已经对 reject 做过处理,不会再进入 catch
      • Promise.all
        • 传入数组,当所有的 Promsie 的 resolve 回调结束再返回
      • Promise.race
        • 传入数组,取最快的 resolve 的回调函数
    • 链式调用
      • 无论是 then 还是 catch 返回都是 this
        • this 是什么?
          • 词法作用域

Promise 引出 Event Loop

  • 事件循环
    • 宏任务、微任务

什么是 Promise

在了解 Promise 前,先去看看为什么会产生 Promise

JavaScript 的回调函数

getAsync('fileA.txt', function (error, result) {
    if (error) {
        //  失败时的处理
        throw err;
    }
    // 成功后的处理
});

Node.Js 的规则是在 JavaScript 的回调函数的第一个参数为 Error 对象,这是它的一个惯例

使用 Promise 进行异步处理

var promise = getAsyncPromise('fileA.txt');
promise
    .then(function (result) {
        // 获取文件内容成功后的处理
    })
    .catch(function (error) {
        // 获取文件内容失败后的处理
    });
// 或者用另一种
promise.then(
    function (result) {
        // 获取文件内容成功后的处理
    },
    function (error) {
        // 获取文件内容失败后的处理
    },
);

看到用 promise 和回调函数的区别没有

promise 更趋于同步的想法——我去调这个行为,等(then)它好了我再执行 XX

综上所述:

promise 是异步编程的一种解决方案,比传统的回调函数和事件更合理和强大

所谓 promise,简单来说就是一个容器,里面保存着某个未来才会结束的行为(通常是一个异步处理)。从语法上讲,promise 是一个对象,从它那可以获取异步操作的消息

实战 Promise

一般用法

之前介绍过,promise 像一个容器,包裹着“成功”或“失败”

function promise() {
    return new Promise(function (resolve, reject) {
        setTimeout(function () {
            resolve('成功');
        }, 1000);
    });
}
promise().then(function (value) {
    console.log(value);
});

then

它的使用

then 方法可以接受两个回调函数作为参数,

第一个回调函数是 promise 对象的状态变为 resolved 的时候调用,

第二个回调函数是 promise 对象的状态变为 rejected 时调用

其中第二个函数时可选的,不一定需要提供

它的作用

为 promise 实例添加状态改变时的回调函数

前面说过,then 方法的第一个参数是 resolved 状态的回调函数,第二个参数是 rejected 状态的回调函数(可选)

then 方法返回的是一个新的 promise 实例。注意,不是原来那个 promise 实例,因此可以采用链式写法,即在 then 方法后面再调用另一个 then 方法

注意:then 方法即不会触发回调,也不会将它放到微任务,then 只负责注册回调,由 resolve 将注册的回调放入微任务队列,由事件循环将其取出并执行

执行顺序

面试中常常考的问题

在说这个之前,需要先聊天事件循环的执行顺序

简单来说:XXX

回过头说 promise,promise 新建后就会立即执行,而 then 会被塞到为微任务中,当宏任务执行完后再执行微任务

promise

Promise 是 ES6 新增的语法,解决了回调地狱的问题

可以把 Promise 堪称一个状态机,初始时 pending 状态,通过函数 resolve 和 rejecy,将状态转变为 resolved 和 rejected,状态一旦改变就不会再次变化

阳波 javascript 核心技术开发解密

1.异步与同步

​ 什么是异步?什么是同步?在代码的执行过程中,经常会涉及两个不同的概念,他们就是同步和异步。

​ 同步是值当发起一个请求时,如果未得到请求结果,代码将会等待,直到结果出来,才会执行后面的代码。异步是指当发起一个请求时,不会等待请求结果,而是直接继续执行后面代码。

​ 我们使用 promise 模拟一个发起请求的函数,该函数执行后,会在 1s 之后返回数值 30

function fn() {
    return new Promise(function (resolve, reject) {
        setTimeout(function () {
            resolve(30);
        }, 1000);
    });
}

在该函数的基础上,可以使用 async/awaut 语法来模拟同步的效果

const foo = async function () {
    const t = await fn();
    console.log(t);
    console.log('next code');
};

foo();
// 输出结果
// 1s 之后依次输出
// 30
// nextcode

而一部效果则会有不同的输出结果:

const foo = function () {
    fn().then(function (res) {
        console.log(res);
    });
    console.log('next code');
};
// 输出结果
// 1s 之后依次输出
// nextcode
// 30

then 方法返回的是一个新的 Promise 实例(注意,不是原来那个 Promise 实例)因此可以采用链式写法,即 then 方法后面再调用另一个 then 方法

实例化 Promise 传入的函数是同步执行的,then 方法本身其实也是同步执行的,但 then 中的回调会先放入微任务队列,等同步任务执行完毕后,再依次取出执行,换句话说只有回调是异步的

在 new Promise 中使用 resolve 或者 reject,相当于变更 promise 的状态,变化后,promise.then 会执行

参考资料

Last Updated:
Contributors: johan