你真的了解Promise吗

101 阅读2分钟

什么是Promise

Promise 对象用于表示一个异步操作的最终完成(或失败)及其结果值。

Promise的三个状态。

  • 待定(pending) :初始状态,既没有被兑现,也没有被拒绝。
  • 已兑现(fulfilled) :意味着操作成功完成。
  • 已拒绝(rejected) :意味着操作失败。

Promise状态之间的流转

image.png

1.Promise 对象初始化状态为 pending
2.当调用resolve(成功),会由pending => fulfilled
3.当调用reject(失败),会由pending => rejected

Promise 比然存在某一种状态,由初始态 pendingfulfilledrejected状态,并且不可更改。

Promise的使用


// 创建了一个promise对象
var promise = new Promise((resolve,reject) => {
    // 执行相应的异步逻辑。
})

// 回调完成调用then方法
promise.then((result)=> {
    console.log(result);
}, reason => {
    console.log(reason) // rejected
})

// reject之后
promise.catch(err=>{
    console.error(err);
});


// Promise.all

const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, 'foo');
});

Promise.all([promise1, promise2, promise3]).then((values) => {
  console.log(values);
});
// expected output: Array [3, 42, "foo"]

// Promise.race
const promise1 = new Promise((resolve, reject) => {
  setTimeout(resolve, 500, 'one');
});

const promise2 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, 'two');
});

Promise.race([promise1, promise2]).then((value) => {
  console.log(value);
  // Both resolve, but promise2 is faster
});
// expected output: "two"


// Promise.allSettled
const promise1 = Promise.resolve(3);
const promise2 = new Promise((resolve, reject) => setTimeout(reject, 100, 'foo'));
const promises = [promise1, promise2];

Promise.allSettled(promises).
  then((results) => results.forEach((result) => console.log(result.status)));
// expected output:
// "fulfilled"
// "rejected"

Promise解决了什么问题

回调地狱

Promise解决了js异步编程中回调地狱的问题,可以形象的看下面这张图

image.png

在Javascript的早期,实现异步编程的主要模式是回调函数。

function f1(callback){
    setTimeout(function () {
      // f1的任务代码
      callback();
    }, 1000);
 }

回调函数的优点是简单、容易理解和部署,缺点是不利于代码的阅读和维护,各个部分之间高度耦合(Coupling),流程会很混乱,而且每个任务只能指定一个回调函数。

代码可读性的问题

有编写大量回调函数组成的代码,可读性不高。而Promise的出现,以一种规范化的方式提供异步编程的范式,可读性提高。

信任问题

在传统的回调式异步编程中,回调函数控制成功或失败后的逻辑。
在Promise的方式中,回调只负责成功之后的通知,而回调成功之后的操作放在了then的回调里面,由Promise精确控制。

手写一个Promise

第一步,我们先创建一个Promise类


// 定义三种状态
const PENDING = "pending";
const REJECTED = "rejected";
const FULFILLED = "fulfilled";

class MPromise {
  status;
  resolveCallbacks = [];
  rejectCallbacks = [];
  constructor(func) {
    this.status = PENDING;
    try {
      func(this.resolve.bind(this), this.reject.bind(this));
    } catch (e) {
      // 兼容throw 报错情况。
      this.reject(e.message);
    }
  }

  resolve(result) {
    setTimeout(() => {
      if (this.status === PENDING) {
        this.status = FULFILLED;
        this.result = result;
        this.resolveCallbacks.forEach((cb) => cb(result));
      }
    });
  }

  reject(result) {
    setTimeout(() => {
      if (this.status === PENDING) {
        this.status = REJECTED;
        this.result = result;
        this.rejectCallbacks.forEach((cb) => cb(result));
      }
    });
  }

  then(onResolve, onReject) {
      return new MPromise((resolve) => {
        if (this.status === PENDING) {
          this.resolveCallbacks.push(onResolve);
          this.rejectCallbacks.push(onReject);
        }

        if (this.status === FULFILLED) {
          setTimeout(() => {
            const res = onResolve(this.result);
          });
        }

        if (this.status === REJECTED) {
          setTimeout(() => {
            onReject(this.result);
          });
        }
      })
  }
}

console.log("第一步");
var promise2 = new MPromise((resolve) => {
  console.log("第二步");
  setTimeout(() => {
    console.log("第四步");
    resolve(0);
    console.log("第五步");
  }, 3000);
});

console.log("第三步");
console.log(promise2);

promise2.then((res) => {
  console.log(res);
  console.log("第六步");
});

参考文章

Promise/A+规范