资讯专栏INFORMATION COLUMN

Promise原理分析一

WilsonLiu95 / 963人阅读

摘要:原理分析一对象用于异步计算。它有两个参数,分别为在成功和失败情况下的回调函数。实现根据当前状态对回调函数进行处理,同时返回一个新的对象,以便链式调用。,注册回调函数到当前的对象中或,立即执行回调函数说明方法只处理被拒绝的情况,并返回一个。

Promise原理分析一

Promise对象用于异步计算。一个Promise对象代表着一个还未完成,但预期将来会完成的操作。

Note:

Promise原理分析二

Promise对象有以下几种状态:

pending: 初始状态, 既不是 fulfilled 也不是 rejected.

fulfilled: 成功的操作.

rejected: 失败的操作.

pending状态的Promise对象既可转换为带着一个成功值的fulfilled状态,也可变为带着一个失败信息的 rejected状态。当状态发生转换时,Promise.then绑定的方法就会被调用。(当绑定方法时,如果 Promise对象已经处于fulfilled或rejected状态,那么相应的方法将会被立刻调用,所以在异步操作的完成情况和它的绑定方法之间不存在竞争条件。)

因为Promise.prototype.then和Promise.prototype.catch方法返回Promises对象, 所以它们可以被链式调用。

constructor 说明

语法

new Promise(executor);
new Promise(function(resolve, reject) { ... });

参数

name desc
executor 带有resolve、reject两个参数的函数对象。第一个参数用在处理执行成功的场景,第二个参数则用在处理执行失败的场景。一旦我们的操作完成即可调用这些函数。
实现

构造函数主要完成状态的初始化,并提供resolvereject两个方法给创建者以转变状态。

const utils = require("./utils");
const isFunction = utils.isFunction;

const STATUS = {
  PENDING: "pending",
  FULFILLED: "fulfilled",
  REJECTED: "rejected"
};

const SYMBOL_STATUS = Symbol("status");
const SYMBOL_DATA = Symbol("data");
const SYMBOL_FULFILLED_CALLBACK = Symbol("fulfilledCallback");
const SYMBOL_REJECTED_CALLBACK = Symbol("rejectedCallback");

class Promise {
  constructor(executor) {
    if (!isFunction(executor)) {
      throw Error(`Promise executor ${executor} is not a function`);
    }

    const self = this;
    // 初始状态为pending
    const status = self[SYMBOL_STATUS] = STATUS.PENDING;

    // 使用symbol实现私有化
    self[SYMBOL_FULFILLED_CALLBACK] = undefined;
    self[SYMBOL_REJECTED_CALLBACK] = undefined;
    self[SYMBOL_DATA] = undefined;

    function resovle(value) {
      // todo
    }

    function reject(reason) {
      // todo
    }

    // 执行executor函数,若出现异常则调用reject方法,将状态变为rejected,同时调用回调函数
    try {
      executor(resovle, reject);
    } catch (err) {
      reject(err);
    }
  }
}

上面代码中完成了构造函数的雏形,而resolvereject两个函数的职责为状态转变和回调函数的调用:

resolve,接受一个成功值,传递给绑定的fulfilled回调函数中。主要工作是将当前状态变为fulfilled状态,同时调用绑定的fulfilled回调函数:

function resovle(value) {
  const fulfilledCallback = self[SYMBOL_FULFILLED_CALLBACK];

  if (status === STATUS.PENDING) {
    self[SYMBOL_STATUS] = STATUS.FULFILLED;  // 状态转换
    self[SYMBOL_DATA] = value;  // 保存成功值

    if (isFunction(fulfilledCallback)) {
      setTimeout(() => {  // 不阻塞主流程,在下一个事件轮询中再调用fulfilled回调函数
        fulfilledCallback(value);
      });
    }
  }
}

reject,接受一个失败信息,传递给绑定的rejected回调函数中。主要工作是将当前状态变为rejected 状态,同时调用绑定的rejected回调函数:

function reject(reason) {
  const rejectedCallback = self[SYMBOL_REJECTED_CALLBACK];

  if (status === STATUS.PENDING) {
    self[SYMBOL_STATUS] = STATUS.REJECTED;  // 状态转换
    self[SYMBOL_DATA] = reason;  // 保存成功值

    if (isFunction(rejectedCallback)) {
      setTimeout(() => {  // 不阻塞主流程,在下一个事件轮询中再调用rejected回调函数
        rejectedCallback(reason);
      });
    }
  }
}

fulfilled`和rejected回调函数是通过Promise.prototype.then和Promise.prototype.catch注册的。

then 说明

then方法返回一个Promise。它有两个参数,分别为Promise在成功和失败情况下的回调函数。

语法

p.then(onFulfilled, onRejected);

p.then(function(value) {
  // todo
}, function(reason) {
  // todo
});

参数

name desc
onFulfilled 一个函数,当Promise的状态为fulfilled时调用。该函数有一个参数,为成功的返回值。
onRejected 一个函数,当Promise的状态为rejected时调用。该函数有一个参数,为失败的原因。
实现

根据当前状态对回调函数进行处理,同时返回一个新的Promise对象,以便链式调用。

then(onFulfilled, onRejected) {
  const self = this;
  const status = self[SYMBOL_STATUS];
  const data = self[SYMBOL_DATA];
  const resolveValue = self[SYMBOL_RESOLVE_VALUE];
  // 如果onFulfilled不是函数,回调函数仅返回成功值
  const fulfilledCallback = isFunction(onFulfilled)
      ? onFulfilled
      : function returnFunc(value) { return value; };
  // 如果onRejected不是函数,回调函数仅返回失败信息
  const rejectedCallback = isFunction(onRejected)
      ? onRejected
      : function throwFunc(reason) { throw reason; };
      
  // 当前状态为pending
  if (status === STATUS.PENDING) {
    // 返回一个新的Promise对象,可以被链式调用
    return new Promise((resolve, reject) => {
      // 将fulfilled回调函数注册到当前Promise对象中(非新Promise对象)
      self[SYMBOL_FULFILLED_CALLBACK] = value => {
        // 根据回调函数的执行情况,通过传递的新Promise对象的resolve和reject方法对其状态进行转变
        try {
          const newValue = fulfilledCallback(value);
          // 解析成功值
          resolveValue(newValue, resolve, reject);
        } catch (err) {
          reject(err);
        }
      };

      // 同上
      self[SYMBOL_REJECTED_CALLBACK] = reason => {
        try {
          const newReason = rejectedCallback(reason);
          resolveValue(newReason, resolve, reject);
        } catch (err) {
          reject(err);
        }
      };
    });
  }

  // 当前状态为fulfilled
  if (status === STATUS.FULFILLED) {
    // 返回一个新的Promise对象,可以被链式调用
    return new Promise((resolve, reject) => {
      // 在下一个事件轮询中立即调用fulfilled回调函数,根据执行情况决定新Promise对象的状态转变
      setTimeout(() => {
        try {
          const newValue = fulfilledCallback(data);
          resolveValue(newValue, resolve, reject);
        } catch (err) {
          reject(err);
        }
      });
    });
  }

  // 当前状态为rejected
  if (status === STATUS.REJECTED) {
    // 返回一个新的Promise对象,可以被链式调用
    return new Promise((resolve, reject) => {
      // 在下一个事件轮询中立即调用rejected回调函数,根据执行情况决定新Promise对象的状态转变
      setTimeout(() => {
        try {
          const newReason = rejectedCallback(data);
          resolveValue(newReason, resolve, reject);
        } catch (err) {
          reject(err);
        }
      });
    });
  }
}

// 解析传递值函数
[SYMBOL_RESOLVE_VALUE](value, resolve, reject) {
  // 若传递值为Promise对象,将新Promise对象的resolve和reject传递给Promise传递值以触发状态的转换
  if (value instanceof Promise) {
    value.then(resolve, reject);
    return;
  }

  // 若传递值不是Promise对象,传递给resolve方法
  resolve(value);
}

根据当前Promise对象的状态,对回调函数进行注册或立即执行,同时返回一个新的Promise对象。

pending,注册回调函数到当前的Promise对象中

fulfilledrejected,立即执行回调函数

catch 说明

catch方法只处理Promise被拒绝的情况,并返回一个Promise。该方法的行为和调用Promise.prototype.then(undefined, onRejected)相同。

语法

p.catch(onRejected);

p.catch(function(reason) {
   // todo
});

参数

name desc
onRejected 当Promise被拒绝时调用的函数。该函数调用时会传入一个参数:失败原因。
实现

catch方法是对then方法的包装,仅传递onRejected失败回调函数。

catch(onRejected) {
  return this.then(null, onRejected);
}
总结

现在回顾下Promise的实现过程,其主要使用了设计模式中的观察者模式:

通过Promise.prototype.then和Promise.prototype.catch方法将观察者方法注册到被观察者Promise对象中,同时返回一个新的Promise对象,以便可以链式调用。

被观察者管理内部pending、fulfilled和rejected的状态转变,同时通过构造函数中传递的resolve和reject方法以主动触发状态转变和通知观察者。

关键知识点

Promise

MDN

symbol

ruanyifeng

观察者模式

百度百科

资源 完整代码

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/80384.html

相关文章

  • Promise原理分析

    摘要:原理分析一说明方法返回一个被拒绝的对象。实现创建一个新的对象,通过其构造函数的参数函数对象将状态变为。和使用解析值,同时通过构造函数的参数的函数对象触发的状态转变,其中使用数组记录返回值使用索引值以确保其返回值在结果集中的顺序。 Promise原理分析二 前面我们分析了Promise的then和catch方法,接下来我们一起来看看reject、resolve、race和all方法的实现...

    OnlyMyRailgun 评论0 收藏0
  • 原理剖析(第 011 篇)Netty之服务端启动工作原理分析(下)

    摘要:原理剖析第篇之服务端启动工作原理分析下一大致介绍由于篇幅过长难以发布,所以本章节接着上一节来的,上一章节为原理剖析第篇之服务端启动工作原理分析上那么本章节就继续分析的服务端启动,分析的源码版本为二三四章节请看上一章节详见原理剖析第篇之 原理剖析(第 011 篇)Netty之服务端启动工作原理分析(下) - 一、大致介绍 1、由于篇幅过长难以发布,所以本章节接着上一节来的,上一章节为【原...

    Tikitoo 评论0 收藏0
  • promise/deferred 模式原理分析和实现

    摘要:三模式模式其实包含两部分和。六化在编码的时候,想要用进行异步操作流程控制,就要将当前的异步回调函数封装成。 一、什么是promise/deferred 模式 promise/deferred 模式是,根据promise/A 或者它的增强修改版promise/A+ 规范 实现的promise异步操作的一种实现方式。 异步的广度使用使得回调,嵌套出现,但是一但出现深度的嵌套,就会让codi...

    gclove 评论0 收藏0
  • js异步发展历史与Promise原理分析

    摘要:异步的发展历史写法意为回调函数,即异步操作执行完后触发执行的函数,例如当请求完成时就会触发函数。实例生成以后,可以用方法分别指定状态和状态的回调函数。第一个回调函数是对象的状态变为时调用,第二个回调函数是对象的状态变为时调用。 关于异步 所谓异步,简单说就是一个任务不是连续完成的,可以理解成该任务被人为分成两段,先执行第一段,然后转而执行其他任务,等做好了准备,再回过头执行第二段。 比...

    jimhs 评论0 收藏0
  • 30分钟,让你彻底明白Promise原理

    摘要:链式是指在当前达到状态后,即开始进行下一个后邻。在中发现没有指定异步操作失败的回调时,会直接将函数返回的,后同设为状态,如此达成执行后续失败回调的效果。 原文链接 前言 前一阵子记录了promise的一些常规用法,这篇文章再深入一个层次,来分析分析promise的这种规则机制是如何实现的。ps:本文适合已经对promise的用法有所了解的人阅读,如果对其用法还不是太了解,可以移步我的上...

    Profeel 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<