删库在逃程序员的Blog

Promise 学习笔记

author
·
24
0

Promise 学习笔记

ES6 异步编程的核心解决方案,彻底理解 Promise 的状态、链式调用与异常处理。

一、Promise 是什么?

1.1 抽象理解

  • 技术规范:ES6 引入的异步编程新标准
  • 解决方案:替代传统回调函数的异步编程方案

1.2 具体表达

角度 描述
语法层面 Promise 是一个构造函数
功能层面 封装异步操作,获取成功/失败的结果值

1.3 状态变化

pending ──→ fulfilled (成功,返回 value)
     └──→ rejected  (失败,返回 reason)

核心规则

  • 只有上述 2 种状态变化
  • 一个 Promise 只能改变一次状态
  • 无论成功或失败,都会有结果数据

1.4 基本使用

// 1. 创建 Promise 对象
const p = new Promise((resolve, reject) => {
  // 2. 执行异步任务
  setTimeout(() => {
    const time = Date.now();
    if (time % 2 === 1) {
      resolve('成功的值 ' + time);
    } else {
      reject('失败的值 ' + time);
    }
  }, 2000);
});

// 3. 绑定回调获取结果
p.then(
  value => console.log('成功:', value),
  reason => console.log('失败:', reason)
);

1.5 实用封装示例

封装定时器异步

function doDelay(time) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const t = Date.now();
      if (t % 2 === 1) {
        resolve('成功:' + t);
      } else {
        reject('失败:' + t);
      }
    }, time);
  });
}

doDelay(2000).then(
  value => console.log(value),
  reason => console.error(reason)
);

封装 Ajax 请求

function promiseAjax(url) {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.onreadystatechange = () => {
      if (xhr.readyState !== 4) return;
      if (xhr.status >= 200 && xhr.status < 300) {
        resolve(JSON.parse(xhr.response));
      } else {
        reject(new Error('请求失败:' + xhr.status));
      }
    };
    xhr.open('GET', url);
    xhr.send();
  });
}

promiseAjax('https://api.example.com/data')
  .then(data => console.log(data))
  .catch(error => console.error(error));

二、为什么使用 Promise?

2.1 更灵活的回调指定

传统回调方式(必须提前指定):

function doSomethingAsync(params, successCallback, failureCallback) {
  setTimeout(() => {
    const result = params % 2 === 0;
    if (result) {
      successCallback(result);
    } else {
      failureCallback(result);
    }
  }, 1000);
}

Promise 方式(可随时绑定):

function doSomethingAsync(params) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const result = params % 2 === 0;
      if (result) resolve(result);
      else reject(result);
    }, 1000);
  });
}

doSomethingAsync(Date.now())
  .then(value => console.log(value))
  .catch(reason => console.error(reason));

2.2 链式调用解决回调地狱

回调地狱示例

doSomething(result => {
  doSomethingElse(result, newResult => {
    doThirdThing(newResult, finalResult => {
      console.log('最终结果:', finalResult);
    }, failureCallback);
  }, failureCallback);
}, failureCallback);

Promise 链式调用

doSomething()
  .then(result => doSomethingElse(result))
  .then(newResult => doThirdThing(newResult))
  .then(finalResult => console.log('最终结果:', finalResult))
  .catch(failureCallback);

async/await 方案(最优雅):

async function request() {
  try {
    const result = await doSomething();
    const newResult = await doSomethingElse(result);
    const finalResult = await doThirdThing(newResult);
    console.log('最终结果:', finalResult);
  } catch (error) {
    failureCallback(error);
  }
}

三、Promise API 详解

API 说明
Promise(executor) 构造函数,executor 立即同步执行
.then(onResolved, onRejected) 绑定回调,返回新 Promise
.catch(onRejected) 捕获异常,等价于 then(undefined, onRejected)
Promise.resolve(value) 返回成功状态的 Promise
Promise.reject(reason) 返回失败状态的 Promise
Promise.all([...]) 全部成功才成功,一个失败即失败
Promise.race([...]) 第一个完成的结果即为最终结果

Promise.all 示例

const p1 = Promise.resolve(1);
const p2 = Promise.resolve(2);
const p3 = new Promise((resolve, reject) => {
  setTimeout(() => resolve(3), 100);
});

Promise.all([p1, p2, p3])
  .then(values => console.log('全部成功:', values))
  .catch(reason => console.error('有失败:', reason));

Promise.race 示例

const slow = new Promise(resolve => 
  setTimeout(() => resolve('慢'), 500)
);
const fast = new Promise(resolve => 
  setTimeout(() => resolve('快'), 100)
);

Promise.race([slow, fast])
  .then(value => console.log('最快的:', value));

四、关键问题解析

4.1 如何改变 Promise 状态?

  1. resolve(value) → pending 变为 fulfilled
  2. reject(reason) → pending 变为 rejected
  3. 抛出异常 → pending 变为 rejected

4.2 状态改变与回调指定的先后顺序

两种情况都可能

  • 正常情况:先指定回调,后改变状态
  • 特殊情况:先改变状态,后指定回调(回调仍会执行)
const p = new Promise((resolve, reject) => {
  resolve('已完成');
});

p.then(value => console.log(value));

4.3 then() 返回的新 Promise 由什么决定?

回调返回值 新 Promise 状态
抛出异常 rejected,reason 为异常
返回非 Promise 值 fulfilled,value 为该值
返回另一个 Promise 与该 Promise 状态一致

4.4 异常传透机制

doSomething()
  .then(result => {
    throw new Error('出错了');
  })
  .then(result => doSomethingElse(result))
  .catch(error => console.error(error));

4.5 中断 Promise 链

doSomething()
  .then(result => {
    if (shouldStop) {
      return new Promise(() => {});
    }
    return result;
  })
  .then(result => {
    // 如果上面中断了,这里不会执行
  });

五、手写 Promise(简化版)

class MyPromise {
  constructor(executor) {
    this.state = 'pending';
    this.value = undefined;
    this.reason = undefined;
    this.onResolvedCallbacks = [];
    this.onRejectedCallbacks = [];

    const resolve = (value) => {
      if (this.state === 'pending') {
        this.state = 'fulfilled';
        this.value = value;
        this.onResolvedCallbacks.forEach(fn => fn());
      }
    };

    const reject = (reason) => {
      if (this.state === 'pending') {
        this.state = 'rejected';
        this.reason = reason;
        this.onRejectedCallbacks.forEach(fn => fn());
      }
    };

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

  then(onFulfilled, onRejected) {
    if (this.state === 'fulfilled') {
      onFulfilled(this.value);
    }
    if (this.state === 'rejected') {
      onRejected(this.reason);
    }
    if (this.state === 'pending') {
      this.onResolvedCallbacks.push(() => onFulfilled(this.value));
      this.onRejectedCallbacks.push(() => onRejected(this.reason));
    }
  }

  catch(onRejected) {
    return this.then(undefined, onRejected);
  }
}

参考资源

评论 (0)