Promise 笔记

340 阅读4分钟

什么是Promise

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

解决了什么

解决了回调嵌套

    // 比如我们有这样的一个需求 请求第一个成功之后, 在第一个成功的基础上 需要调用 第二个接口... 一次类推  两层还能接受, 但是如果是 4层 基本上就很难维护,和阅读
    previewinit(id, tenantId, row)
        .then( () => {
            previewresult(statementId,clusterId)
                .then( () =>{
                    getSchema()
                        .then()
                })
        })
        // 在没有写逻辑的情况下已经很难读懂是什么意思了

对于几种常见异步编程方案

  1. 回到函数
  2. 时间监听
  3. 发布/订阅(可以看这篇文章)

Promise 的两个特点

  1. 对象的状态不受外界影响

        // 有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。
        const promise = new Promise(function(resolve, reject) {
            if (/* 异步操作成功 */){
                resolve(value);
            } else {
                reject(error);
            }
        });
    
  2. 一旦状态改变,就不会在变

         // 只有两种可能:从pending变为fulfilled和从pending变为rejected。
    

Promise 新建后就会立即执行

    let promise = new Promise(function(resolve, reject) {
        // 我们并没有调用 Promise 但是也是先执行啦
        console.log('Promise');
        resolve();
    });

    promise.then(function() {
    console.log('resolved.');
    });

    console.log('Hi!');
    // Promise  首先输出
    // Hi!
    // resolved

在函数内使用 Promise 需要 return promise

    function loadImage () {
        let promise = new Promise(function (resolve, reject) {
            // some code
        })
        // 只有返回出去 外部才能拿到 promise 的实例
        return promise
    }

需要注意

resolved 的 Promise 是在本轮事件循环的末尾执行,总是晚于本轮循环的同步任务。

    let promise = new Promise(function (resolve, reject) {
        resolve(1)
        console.log(2)
    })
    promise.then((result) => console.log(result))
    // 2
    // 1
    let promise = new Promise(function (resolve, reject) {
        // 一般情况下 我们执行 resolve 之后是不需要在执行后边的代码的所有使用 return
        return resolve(1)
        console.log(2)
    })
    promise.then((result) => console.log(result))

Promise.prototype.then()

  1. then方法是定义在原型对象Promise.prototype上的
  2. 可是使用链式操作
  3. then方法返回的是一个新的Promise实例(注意,不是原来那个Promise实例)
  4. 第一个回调函数完成以后,会将返回结果作为参数,传入第二个回调函数。
    getJSON("/posts.json").then(function(json) {
        return json.post;
    }).then(function(post) {
        // ...
    });

Promise.prototype.catch()

  1. .then(null, rejection) 或 .then(undefined, rejection) 的别名
  2. 用于指定发生错误的对调函数
  3. 如果状态已经变成resolved,再抛出错误是无效的。
  4. Promise 对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止。也就是说,错误总是会被下一个catch语句捕获。
  5. 建议总是使用catch方法,而不使用then方法的第二个参数。
  6. Promise 内部的错误不会影响到 Promise 外部的代码,

Promise.prototype.finally()

  1. 不管promise最后的状态,在执行完then或catch指定的回调函数以后,都会执行finally方法指定的回调函数。
  2. 回调函数 不接受任何参数, 不知道状态是成功还是失败, 所以与状态无关
  3. 如果 成功和失败都需要些同样的逻辑 则可以直接使用 finally
    server.listen(port)
    .then(function () {
        // ...
    })
    // finally方法关掉服务器。
    .finally(server.stop);

Promise.all()

  1. 方法接受一个数组作为参数 每个值都是 Promise 的实例 参数可以不是数组,但必须具有 Iterator 接口
  2. 如果作为参数的 Promise 实例,自己定义了catch方法,那么它一旦被rejected,并不会触发Promise.all()的catch方法。
  3. 实例的状态都变成fulfilled,或者其中有一个变为rejected,才会调用Promise.all方法后面的回调函数。

Promise.race()

const p = Promise.race([p1, p2, p3]);

  1. 方法接受一个数组作为参数
  2. 只要其中有一个实例率先改变状态,P的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。
  3. 如果指定时间内没有获得结果,就将 Promise 的状态变为reject,否则变为resolve
   let p1 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('success')
    },1000)
    })

    let p2 = new Promise((resolve, reject) => {
    setTimeout(() => {
        reject('failed')
    }, 500)
    })

    Promise.race([p1, p2]).then((result) => {
        // 这里不会执行
        console.log(result)
    }).catch((error) => {
        console.log(error)  // 打印的是 'failed'
    })

Promise.allSettled()

  1. 我们不关心异步操作的结果,只关心这些操作有没有结束。这时,Promise.allSettled()方法就很有用。

Promise.any()

  1. 方法接受一个数组作为参数
  2. 只要参数实例有一个变成fulfilled状态,包装实例就会变成fulfilled状态;如果所有参数实例都变成rejected状态,包装实例就会变成rejected状态。

Promise.resolve()

  1. 把现有对象转成 Promise 对象
  2. resolve()的 Promise 对象,是在本轮“事件循环”(event loop)的结束时执行,而不是在下一轮“事件循环”的开始时。
  3. 可以理解为 让一个对象有 then 方法
    var promise1 = Promise.resolve(123);
    promise1.then(function(value) {
        console.log(value);
        // expected output: 123
    });
    setTimeout(function () {
        console.log('three');
    }, 0);

    Promise.resolve().then(function () {
        console.log('two');
    });

    console.log('one');

    // one
    // two
    // three