Typescript-Promise基础

www.jswusn.com JS 2025-06-10 17:02:30 7次浏览


Promise 文档[1]

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

从函子的角度对 Promise 做一下构建

首先构造一个常规的容器

class Option<T> {
  private value: T | null;

  private constructor(value: T | null) {
    //思考:如果是异步赋值应该如何处理?
    this.value = value;
  }

  static some<T>(value: T | Option<T>): Option<T> {
    if (value instanceof Option) {
      return value;
    }
    return new Option(value);
  }

  map<U>(fn: (value: T) => U): Option<U> {
    return this.value === null ? Option.none<U>() : Option.some(fn(this.value));
  }

  flatMap<U>(fn: (value: T) => Option<U>): Option<U> {
    return this.value === null ? Option.none<U>() : fn(this.value);
  }
}


实现 map 包装任意值并且返回自身构造一个自函子

// 拍平结构 Some(1)
const option = Option.some(Option.some(1));
// 链式调用
const add1 = (value: number) => value + 1;
const add2 = (value: number) => value + 2;
const multiply = (value: number) => value * 2;
const result = option.map(add1).map(add2).map(multiply);
// Some(8)

Option有两个状态,SomeNone

Promise可以模仿这个结构,但是我们遇到的问题是取值是异步的,并且可能失败

即上文Optionconstruct是一个异步状态

那么我们只能传一个回调resolve来处理结果 来实现拿到值之后再进行计算

对称的我们需要一个reject来处理失败的状态

按照规范Promise有三个状态

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

type PromiseStatus = (typeof PROMISE_STATUS)[keyof typeof PROMISE_STATUS];

初始值为pending 只能扭转一次

  • • 成功之后扭转为fulfilled执行resolve
  • • 失败之后扭转为rejected执行reject
resolve(value: T) {
    this.status = PROMISE_STATUS.FULFILLED;
    this.value = value;
}

reject(reason: string) {
    this.status = PROMISE_STATUS.REJECTED;
    this.reason = reason;
}

Promise 实现

先看类型签名,在Typescriptnode_modules文件下

可以看到lib.*.promise.d.ts的构造签名

interface PromiseConstructor {
  new <T>(
    executor: (
      resolve: (value: T | PromiseLike<T>) => void,
      reject: (reason?: any) => void
    ) => void
  ): Promise<T>;
}

new函数的签名可以知道,Promise的参数是一个立即执行函数executor

executor有两个参数,并返回一个Promise<T>

  • • resolve 接受一个返回值,可以是另一个 Promise
  • • reject 接受一个 reason

结合上面一部分Promise的状态扭转,完成第一版

class MyPromise<T> {
  status: PromiseStatus = PROMISE_STATUS.PENDING;
  value: T | undefined;
  reason?: any;

  constructor(
    executor: (
      resolve: (value: T) => void,
      reject: (reason: any) => void
    ) => void
  ) {
    const resolve = (value: T) => {
      if (this.status === PROMISE_STATUS.PENDING) {
        this.status = PROMISE_STATUS.FULFILLED;
        this.value = value;
      }
    };

    const reject = (reason: any) => {
      if (this.status === PROMISE_STATUS.PENDING) {
        this.status = PROMISE_STATUS.REJECTED;
        this.reason = reason;
      }
    };

    try {
      executor(resolve, reject);
    } catch (error) {
      reject(error);
    }
  }
}

继续查看Promise的接口定义

interface Promise<T> {
  then<TResult1 = T, TResult2 = never>(
    onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null,
    onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null,
  ): Promise<TResult1 | TResult2>;

  catch<TResult = never>(
    onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null,
  ): Promise<T | TResult>;
}


then接受onfulfilled函数和onrejected函数 返回一个 Promise<T>

catch接受onrejected函数返回一个Promise<T>

then的异步执行

const promise = new Promise((resolve) => {
  setTimeout(() => {
    resolve(1);
  }, 1000);
});

promise.then((x) => console.log(x));


then里回调函数需要等resolve调用之后才执行

then的链式调用

const promise = new Promise((resolve) => {
  setTimeout(() => resolve(1), 1000);
});

promise
  .then((x) => x + 1)
  .then((x) => x * 2)
  .then(console.log);

链式调用的多个then 每个 then 都会返回一个新的Promise

每个Promise都要等前一个Promise的状态改变才能执行

所以还需要有一个队列来放置这些回调函数

对称的有onFulfilledCallbacksonRejectedCallbacks

自返回结构

then里还可以返回Promise

Promise.resolve(1)
  .then((x) => {
    return Promise.resolve(x + 1); // 返回一个新的Promise
  })
  .then((x) => console.log(x)); // 2

Promise.resolve(1)
  .then((x) => Promise.resolve(x + 1)) // 返回Promise<number>
  .then((x) => x + 1) // 自动解包,x是number类型
  .then(console.log); // 3


实际应用场景,根据上一步的结果拉取下一个结构

// 模拟API调用
function fetchUser(id: number) {
  return Promise.resolve({ id, name: "John" });
}

function fetchUserPosts(userId: number) {
  return Promise.resolve([
    { id: 1, title: "Post 1" },
    { id: 2, title: "Post 2" },
  ]);
}

// 链式调用
fetchUser(1)
  .then((user) => {
    return fetchUserPosts(user.id); // 返回新的Promise
  })
  .then((posts) => console.log(posts));

我们编写一个resolvePromise来处理解包的情况

一共三个特例

  • • Promise返回自己,构成循环调用 直接报错
  • • 返回PromiseLike的方法,继续调用返回值的then方法 直到变成值为止
  • • 非PromiseLike,直接返回值

代码如下

function resolvePromise<T>(
  promise2: MyPromise<T>,
  x: any,
  resolve: (value: T) => void,
  reject: (reason: any) => void
) {
  // 1. 如果 promise2 和 x 相同,抛出 TypeError
  if (promise2 === x) {
    return reject(new TypeError("Chaining cycle detected for promise"));
  }

  // 标记是否已调用,防止多次调用
  let called = false;

  // 2. 如果 x 是 MYPromise 实例
  if (x instanceof MyPromise) {
    // 根据 x 的状态调用 resolve 或 reject
    x.then(
      (y) => {
        resolvePromise(promise2, y, resolve, reject);
      },
      (reason) => {
        reject(reason);
      }
    );
  } else if (x !== null && (typeof x === "object" || typeof x === "function")) {
    // 3. PromiseLike
    try {
      // 获取 x 的 then 方法
      const then = x.then as MyPromise<T>["then"];
      if (typeof then === "function") {
        // 如果 then 是函数
        // 使用 x 作为上下文调用 then 方法
        then.call(
          x,
          (y) => {
            // 成功回调
            if (called) return; // 如果已经调用过,直接返回
            called = true;
            // 递归处理 y
            resolvePromise(promise2, y, resolve, reject);
          },
          (reason) => {
            // 失败回调
            if (called) return; // 如果已经调用过,直接返回
            called = true;
            reject(reason);
          }
        );
      } else {
        // 如果 then 不是函数
        // 直接调用 resolve
        resolve(x);
      }
    } catch (error) {
      // 如果获取或调用 then 方法抛出异常
      if (called) return; // 如果已经调用过,直接返回
      called = true;
      reject(error);
    }
  } else {
    // 4. 如果 x 不是对象或函数
    // 直接调用 resolve
    resolve(x);
  }
}


然后就可以完善 then 方法了

 then(onFulfilled: (value?: T) => void, onRejected: (reason: any) => void) {
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
    // prettier-ignore
    onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason; };

    const promise2 = new MyPromise((resolve, reject) => {
      switch (this.status) {
        case PROMISE_STATUS.FULFILLED: {
          setTimeout(() => {
            try {
              const x = onFulfilled(this.value);
              resolvePromise(promise2, x, resolve, reject);
            } catch (error) {
              onRejected(error);
            }
          });
          break;
        }
        case PROMISE_STATUS.REJECTED:
          setTimeout(() => {
            try {
              const x = onRejected(this.reason);
              resolvePromise(promise2, x, resolve, reject);
            } catch (error) {
              reject(error);
            }
          });
          break;
        case PROMISE_STATUS.PENDING: {
          this.onFulfilledCallbacks.push(() => {
            setTimeout(() => {
              try {
                const x = onFulfilled(this.value);
                resolvePromise(promise2, x, resolve, reject);
              } catch (error) {
                reject(error);
              }
            });
          });
          this.onRejectedCallbacks.push(() => {
            setTimeout(() => {
              try {
                const x = onRejected(this.reason);
                resolvePromise(promise2, x, resolve, reject);
              } catch (error) {
                reject(error);
              }
            });
          });
          break;
        }
      }
    });

    return promise2;
  }

验证实现

规范[2]

测试用例[3]

import { createRequire } from "module";
import MyPromise from "./myPromise.ts";

const require = createRequire(import.meta.url);
const promisesAplusTests = require("promises-aplus-tests");

const adapter = {
  resolved: (value: any) => MyPromise.resolve(value),
  rejected: (reason: any) => MyPromise.reject(reason),
  deferred: () => {
    let resolve: (value: any) => void;
    let reject: (reason: any) => void;
    const promise = new MyPromise(
      (res: (value: any) => void, rej: (reason: any) => void) => {
        resolve = res;
        reject = rej;
      }
    );
    return {
      promise,
      resolve: resolve!,
      reject: reject!,
    };
  },
};

promisesAplusTests(adapter, function (err: any) {
  if (err) {
    console.error("测试失败:", err);
    process.exit(1);
  }
  console.log("所有测试通过!");
});


引用链接

[1] Promise 文档: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise
[2] 规范: https://github.com/promises-aplus/promises-spec
[3] 测试用例: https://github.com/promises-aplus/promises-tests


技术分享

苏南名片

  • 联系人:吴经理
  • 电话:152-1887-1916
  • 邮箱:message@jswusn.com
  • 地址:江苏省苏州市相城区

热门文章

Copyright © 2018-2025 jswusn.com 版权所有

技术支持:苏州网站建设  苏ICP备18036849号