# Promise的相关题目

```js
async function async1() {
  console.log("async1 start");
  await async2();
  console.log("async1 end");
}
async function async2() {
  console.log("async2");
}
console.log("script start");
setTimeout(function () {
  console.log("setTimeout");
}, 0);
async1();
new Promise(function (resolve) {
  console.log("promise1");
  resolve();
  console.log("promise2");
}).then(function () {
  console.log("promise3");
});
console.log("script end");

---------------------------

console.log("script start");
console.log("async1 start");
console.log("async2");
console.log("promise1");
console.log("script end");
console.log("async1 end");
console.log("promise2");
console.log("setTimeout");
```

\--不对

```js
async function async1() {
  console.log("async1_start_2");
  await async2();
  console.log("async1_end_6");
  return "async_return_8";
}

async function async2() {
  console.log("async2_3");
}

console.log("script_start_1");

setTimeout(function () {
  console.log("setTimeout_9");
}, 0);

async1().then(function (message) {
  console.log(message);
});

new Promise(function (resolve) {
  console.log("promise_4");
  resolve();
}).then(function () {
  console.log("promise_7");
});

console.log("script_end_5");
```

![](/files/KnA69FdaNJjXGZHSjdh4)

我们在做的时候 写出我们的任务队列

宏任务队列： setTimeout\
微任务队列：none

async1 开始执行，当函数里遇到 await 时，暂停执行（await 所在行放在本次执行完），而 async1 函数 未完成部分被添加到宏任务队列

宏任务队列：async1 setTimeout\
微任务队列：none

new Promise() 实例对象被 new 出来后，它里面的 promise1 会立刻打印，然后又遇到 then, 此时 promise 实例 被添加到微任务队列；

宏任务队列：async1 setTimeout\
微任务队列：promise 实例

由于异步代码第一次执行时，async1 函数 要早于 promise 对象，所以紧接着 async1 函数继续执行没有执行完成的部分（例三中 promise.then 先于 await，所以 then 先执行），执行完毕后，退出任务队列，打印：async1 end。然后把它的 then 逻辑添加到任务微任务队列中;

​ 此时的任务队列：

宏任务队列：setTimeout

微任务队列：promise 实例 ，async1 的 then 逻辑部分

先清空微任务队列，promise 实例 继续执行它的 then 的逻辑，打印：promise2。执行完毕后，退出微任务队列；

​ 此时的任务队列：

宏任务队列：setTimeout

微任务队列：async1 的 then 逻辑部分

async 函数执行 then 逻辑；

此时的任务队列：

宏任务队列：setTimeout

微任务队列：none

setTimeout 是宏任务会在最后执行。

await 后面的代码虽然算作宏任务，但是和普通的微任务不在一个维度，位于更上一层的任务队列，所以优先度要比其他（下层）微任务要高；

定时器为什么是不精确的\
因为定时器是异步的，要等到同步任务执行完之后，才会去执行异步的任务，即使 setTimeout(0)中时间为 0 也不是立马执行。再者 w3c 在 HTML 标准中规定，要求 setTimeout 时间低于 4ms 的都按 4ms 来算。

解决方法： 使用 web Worker 将定时函数作为独立线程执行

```js
new Promise((resolve, reject) => {
  resolve("success");
  console.log("new Promise");
});
console.log("finished");
```

构造函数内部的代码是立即执行的,then 是异步的

```js
Promise.resolve(1)
  .then((res) => {
    console.log(res); // => 1
    return 2; // 包装成 Promise.resolve(2)
  })
  .then((res) => {
    console.log(res); // => 2
  });
```

Promise 实现了链式调用，也就是说每次调用 then 之后返回的都是一个 Promise，并且是一个全新的 Promise，原因也是因为状态不可变。如果你在 then 中 使用了 return，那么 return 的值会被 Promise.resolve()包装

Promise 构造函数是同步，then 是异步

Promise 构造函数中是立即执行（同步任务），then 函数分发到微任务 Event Queue（异步任务），setTimeout 是分发到宏任务中

实现 promise

```js
class MyPromise {
  constructor(executor) {
    this.state = "pending"; // pending, fulfilled, rejected
    this.value = undefined;
    this.reason = undefined;
    this.onFulfilledCallbacks = [];
    this.onRejectedCallbacks = [];
    this.isCancelled = false; // 新增：取消标记

    // 保存 resolve 和 reject 的引用，以便在取消时调用
    const resolve = (value) => this.resolve(value);
    const reject = (reason) => this.reject(reason);

    // 提供取消方法给 executor
    const cancel = () => this.cancel();

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

  resolve(value) {
    if (this.state === "pending" && !this.isCancelled) {
      this.state = "fulfilled";
      this.value = value;
      setTimeout(() => {
        if (!this.isCancelled) {
          this.onFulfilledCallbacks.forEach((callback) => callback(value));
        }
      }, 0);
    }
  }

  reject(reason) {
    if (this.state === "pending" && !this.isCancelled) {
      this.state = "rejected";
      this.reason = reason;
      setTimeout(() => {
        if (!this.isCancelled) {
          this.onRejectedCallbacks.forEach((callback) => callback(reason));
        }
      }, 0);
    }
  }

  then(onFulfilled, onRejected) {
    return new MyPromise((resolve, reject) => {
      const fulfilledHandler = () => {
        if (this.isCancelled) return; // 如果已取消，不执行
        try {
          if (typeof onFulfilled !== "function") {
            resolve(this.value);
          } else {
            const result = onFulfilled(this.value);
            if (result instanceof MyPromise) {
              result.then(resolve, reject);
            } else {
              resolve(result);
            }
          }
        } catch (error) {
          reject(error);
        }
      };

      const rejectedHandler = () => {
        if (this.isCancelled) return; // 如果已取消，不执行
        try {
          if (typeof onRejected !== "function") {
            reject(this.reason);
          } else {
            const result = onRejected(this.reason);
            if (result instanceof MyPromise) {
              result.then(resolve, reject);
            } else {
              resolve(result);
            }
          }
        } catch (error) {
          reject(error);
        }
      };

      if (this.state === "fulfilled") {
        setTimeout(fulfilledHandler, 0);
      } else if (this.state === "rejected") {
        setTimeout(rejectedHandler, 0);
      } else if (this.state === "pending") {
        this.onFulfilledCallbacks.push(fulfilledHandler);
        this.onRejectedCallbacks.push(rejectedHandler);
      }
    });
  }

  // 新增：取消方法
  cancel() {
    if (this.state === "pending") {
      this.isCancelled = true;
      this.onFulfilledCallbacks = []; // 清空回调
      this.onRejectedCallbacks = [];
      this.state = "cancelled"; // 可选：标记为已取消状态
    }
  }

  static all(promises) {
    return new MyPromise((resolve, reject) => {
      const results = [];
      let completedCount = 0;
      const total = promises.length;

      if (total === 0) {
        resolve(results);
        return;
      }

      promises.forEach((promise, index) => {
        MyPromise.resolve(promise).then(
          (value) => {
            results[index] = value;
            completedCount++;
            if (completedCount === total) {
              resolve(results);
            }
          },
          (reason) => {
            reject(reason);
          }
        );
      });
    });
  }

  static race(promises) {
    return new MyPromise((resolve, reject) => {
      if (promises.length === 0) return;

      promises.forEach((promise) => {
        MyPromise.resolve(promise).then(
          (value) => resolve(value),
          (reason) => reject(reason)
        );
      });
    });
  }

  static resolve(value) {
    if (value instanceof MyPromise) return value;
    return new MyPromise((resolve) => resolve(value));
  }

  // 新增：创建可取消的 Promise
  static cancellable(executor) {
    let cancelFn;
    const promise = new MyPromise((resolve, reject, cancel) => {
      cancelFn = cancel; // 保存取消函数
      executor(resolve, reject, cancel);
    });
    return {
      promise,
      cancel: () => cancelFn(),
    };
  }
}

// 测试可取消 Promise
const { promise, cancel } = MyPromise.cancellable((resolve, reject) => {
  console.log("开始执行");
  const timeout = setTimeout(() => {
    resolve("成功");
  }, 2000);

  // 在取消时清理资源
  return () => clearTimeout(timeout);
});

promise.then(
  (value) => console.log("结果:", value), // 如果未取消，输出 "结果: 成功"
  (reason) => console.log("失败:", reason)
);

setTimeout(() => {
  cancel(); // 500ms 后取消
  console.log("已取消");
}, 500);
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://shenjunhong.gitbook.io/blog/mian-shi/zhen-dui-zi-jie/promise-de-xiang-guan-ti-mu.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
