深入理解Promise

简介: 深入理解Promise

原文合集地址如下,有需要的朋友可以关注

本文地址

合集地址

什么是Promise

当谈论 Promise 时,可以将其比喻为一种承诺或契约,用于处理异步操作的结果。异步操作是指那些不会立即完成的操作,比如从服务器获取数据、读取文件、发送网络请求等等。通常情况下,这些操作需要一定的时间来完成。

Promise 的主要目的是在异步操作完成后,通过 Promise 对象来获取操作的结果或处理操作的失败情况。Promise 可以有三种状态:进行中(Pending)、已成功(Fulfilled)和已失败(Rejected)。

  1. 进行中(Pending):Promise 刚被创建时的初始状态,表示异步操作正在进行中,尚未完成或失败。

  2. 已成功(Fulfilled):当异步操作成功完成时,Promise 的状态变为已成功,同时携带着异步操作的结果值。

  3. 已失败(Rejected):当异步操作失败时,Promise 的状态变为已失败,同时携带着失败的原因,通常是一个错误对象。

创建一个 Promise对象需要使用 new Promise() 构造函数,它接收一个带有 resolvereject 两个参数的执行函数作为参数:

const myPromise = new Promise((resolve, reject) => {
   
  // 异步操作(例如,从服务器获取数据或读取文件)
  // 如果异步操作成功,调用 resolve 并传递结果值
  // 如果异步操作失败,调用 reject 并传递失败原因
});

resolve 函数用于将 Promise 状态从进行中转换为已成功,而 reject 函数用于将状态从进行中转换为已失败。

一旦创建了 Promise 对象,就可以通过使用 .then() 方法来添加异步操作成功的回调,并使用 .catch() 方法来添加异步操作失败的回调:

myPromise.then((result) => {
   
  // 异步操作成功,获取 result 结果值
}).catch((error) => {
   
  // 异步操作失败,获取 error 失败原因
});

Promise 还支持链式调用,
可以通过多次使用 .then() 方法来串联多个异步操作:

myPromise.then((result) => {
   
  // 第一个异步操作成功,获取 result 结果值
  // 返回一个新的 Promise 对象
  return anotherAsyncOperation(result);
}).then((anotherResult) => {
   
  // 第二个异步操作成功,获取 anotherResult 结果值
}).catch((error) => {
   
  // 如果任何一个异步操作失败,获取 error 失败原因
});

Promise 的主要方法:

  1. Promise.prototype.then(onFulfilled, onRejected):用于添加异步操作成功(Fulfilled)和失败(Rejected)的回调函数。onFulfilled 是异步操作成功时的回调函数,接收成功的结果值作为参数;onRejected 是异步操作失败时的回调函数,接收失败的原因作为参数。

  2. Promise.prototype.catch(onRejected):用于添加异步操作失败的回调函数,相当于 .then(null, onRejected)

  3. Promise.prototype.finally(onFinally):在 Promise 的状态变为 Fulfilled 或 Rejected 时,都会执行 onFinally 回调函数。该方法不接收任何参数,它返回一个新的 Promise 对象,该 Promise 对象的状态和值与原始 Promise 对象一致。

  4. Promise.resolve(value):返回一个以给定值 value 解析的 Promise 对象。如果 value 是一个 Promise 对象,则直接返回它;如果 value 是一个 thenable 对象(即具有 then 方法的对象),则会将它转换成一个 Promise 对象并返回。

  5. Promise.reject(reason):返回一个以给定原因 reason 拒绝的 Promise 对象。

下面是一个简单的示例,展示如何使用 Promise 来处理异步操作:

function fetchUserData() {
   
  return new Promise((resolve, reject) => {
   
    // 模拟异步请求
    setTimeout(() => {
   
      const userData = {
    name: 'John', age: 30 };
      // 模拟异步请求成功
      resolve(userData);
      // 模拟异步请求失败
      // reject(new Error('Failed to fetch user data'));
    }, 1000);
  });
}

// 使用 Promise
fetchUserData()
  .then((userData) => {
   
    console.log('用户信息:', userData);
  })
  .catch((error) => {
   
    console.error('错误:', error.message);
  })
  .finally(() => {
   
    console.log('异步操作完成');
  });

在上面的示例中,fetchUserData 函数返回一个 Promise 对象,该 Promise 对象模拟了一个异步请求,1秒后成功完成,并返回一个用户信息对象。可以使用 .then 方法添加成功回调,并使用 .catch 方法添加失败回调。在 finally 回调中,无论异步操作成功或失败,都会执行 finally 中的代码。

  1. Promise.all(iterable):该方法接收一个可迭代对象(例如数组)作为参数,其中的每个元素都是 Promise 对象。它返回一个新的 Promise 对象,该 Promise 对象在所有输入的 Promise 都成功完成时才会成功,并将成功的结果值作为数组返回,如果有任何一个输入的 Promise 失败,则返回失败的原因。
const promise1 = Promise.resolve(1);
const promise2 = new Promise((resolve) => setTimeout(() => resolve(2), 1000));
const promise3 = fetch('https://api.example.com/data');

Promise.all([promise1, promise2, promise3])
  .then((results) => {
   
    console.log('所有 Promise 都成功完成,结果值:', results);
  })
  .catch((error) => {
   
    console.error('其中一个 Promise 失败,原因:', error);
  });
  1. Promise.allSettled(iterable):该方法与 Promise.all 类似,接收一个可迭代对象作为参数,返回一个新的 Promise 对象,在所有输入的 Promise 都完成(无论成功或失败)时才会成功。它将以包含每个 Promise 的结果状态的对象数组进行解析,每个对象都有一个 status 字段,可能的值是 "fulfilled""rejected",以及一个 valuereason 字段分别包含了成功的结果值或失败的原因。
const promise1 = Promise.resolve(1);
const promise2 = Promise.reject(new Error('Rejected promise'));
const promise3 = new Promise((resolve) => setTimeout(() => resolve(3), 2000));

Promise.allSettled([promise1, promise2, promise3])
  .then((results) => {
   
    console.log('所有 Promise 完成(成功或失败),结果:', results);
  });
  1. Promise.race(iterable):该方法与 Promise.all 类似,接收一个可迭代对象作为参数,返回一个新的 Promise 对象,该 Promise 对象在输入的 Promise 中有任意一个完成(成功或失败)时就会完成,并将完成的结果值或失败的原因传递给回调。
const promise1 = new Promise((resolve) => setTimeout(() => resolve('Promise 1'), 1000));
const promise2 = new Promise((resolve) => setTimeout(() => resolve('Promise 2'), 2000));

Promise.race([promise1, promise2])
  .then((result) => {
   
    console.log('第一个完成的 Promise 结果:', result);
  });

promise优势与弊端

Promise 的作用和优点:

  1. 处理异步操作:Promise 是 JavaScript 中处理异步操作的一种标准方式。它提供了一种优雅的方式来管理和处理异步代码,避免了回调地狱(Callback Hell)问题,使代码更易读、维护和理解。

  2. 优化性能:Promise 可以帮助优化性能,避免不必要的函数创建和组件重新渲染。使用 Promise.allPromise.race 等方法可以处理多个异步操作,等待它们全部完成或只要有一个完成即可,提高应用的性能和响应性。

  3. 异常处理:Promise 允许通过 .catch 方法统一处理异步操作的错误,使错误处理更加方便和一致。它还可以通过 try/catch 语句处理同步代码中的异常,使异常处理更加统一和简洁。

  4. 支持链式调用:Promise 的 .then.catch 方法支持链式调用,可以方便地对多个异步操作进行串联和组合。

  5. 可以通过 Promise.resolvePromise.reject 方法创建已解决或已拒绝的 Promise,方便进行异步操作的初始化。

Promise 的弊端:

  1. 不支持取消:Promise 一旦创建,就无法取消或终止它的执行。一旦 Promise 进入 Pending 状态,它会继续执行,无法中途停止。

  2. 无法处理多个结果:Promise 只能解决一次,一旦 Promise 进入 Fulfilled 或 Rejected 状态,它的状态就不会改变。因此,它无法处理需要多次结果的场景。

  3. 不支持超时:Promise 本身不支持超时设置,无法直接控制异步操作的超时时间。

  4. 回调地狱的替代方案:虽然 Promise 解决了回调地狱的问题,但是当 Promise 的链式调用过于复杂时,可能会导致代码嵌套和可读性降低。

  5. 需要兼容性处理:在某些较旧的浏览器中,可能需要进行 Promise 的兼容性处理,或者使用 polyfill 来支持 Promise。

手写实现一个Promise

class MyPromise {
   
  constructor(executor) {
   
    // 初始化 Promise 的状态和值
    this.state = 'pending';
    this.value = undefined;

    // 定义 resolve 和 reject 函数
    const resolve = (value) => {
   
      if (this.state === 'pending') {
   
        this.state = 'fulfilled';
        this.value = value;
      }
    };

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

    try {
   
      // 执行 executor 函数,并传入 resolve 和 reject 函数
      executor(resolve, reject);
    } catch (error) {
   
      // 如果执行过程中捕获到异常,将 Promise 状态改为 rejected
      reject(error);
    }
  }

  then(onFulfilled, onRejected) {
   
    // 如果没有传入 onFulfilled 或 onRejected,则创建一个默认的函数来传递值或原因
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (value) => value;
    onRejected = typeof onRejected === 'function' ? onRejected : (reason) => {
    throw reason; };

    return new MyPromise((resolve, reject) => {
   
      // 根据 Promise 的状态执行对应的回调函数
      if (this.state === 'fulfilled') {
   
        setTimeout(() => {
   
          try {
   
            const result = onFulfilled(this.value);
            resolve(result);
          } catch (error) {
   
            reject(error);
          }
        }, 0);
      } else if (this.state === 'rejected') {
   
        setTimeout(() => {
   
          try {
   
            const result = onRejected(this.value);
            resolve(result);
          } catch (error) {
   
            reject(error);
          }
        }, 0);
      } else if (this.state === 'pending') {
   
        // 如果 Promise 的状态还是 pending,将回调函数添加到待处理队列中
        this.onFulfilledCallbacks.push(() => {
   
          setTimeout(() => {
   
            try {
   
              const result = onFulfilled(this.value);
              resolve(result);
            } catch (error) {
   
              reject(error);
            }
          }, 0);
        });

        this.onRejectedCallbacks.push(() => {
   
          setTimeout(() => {
   
            try {
   
              const result = onRejected(this.value);
              resolve(result);
            } catch (error) {
   
              reject(error);
            }
          }, 0);
        });
      }
    });
  }

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

// 示例用法:
const myPromise = new MyPromise((resolve, reject) => {
   
  setTimeout(() => {
   
    const random = Math.random();
    if (random > 0.5) {
   
      resolve('Success!');
    } else {
   
      reject(new Error('Failed!'));
    }
  }, 1000);
});

myPromise
  .then((result) => {
   
    console.log('Fulfilled:', result);
    return 'Resolved Value';
  })
  .then((value) => {
   
    console.log('Chained then:', value);
  })
  .catch((error) => {
   
    console.error('Rejected:', error);
  });

这个简化的 Promise 实现包含 resolve 和 reject 函数、then 方法、catch 方法,以及对异步操作的处理。这个实现并没有处理异步回调函数的执行顺序,真实的 Promise 实现还需要处理更多细节,例如异步操作的执行、错误处理、Promise 链的调用顺序等。完整的 Promise 实现需要更复杂的处理逻辑和边界情况的考虑。

目录
相关文章
|
6月前
|
前端开发 API 容器
说说你对 promise 的了解
说说你对 promise 的了解
33 0
|
前端开发 小程序 JavaScript
promise 应用
promise 应用
58 0
|
前端开发 JavaScript 测试技术
6 # 实现简单的 promise
6 # 实现简单的 promise
38 0
|
3月前
|
前端开发 JavaScript
Promise相关的理解
总之,Promise 是现代 JavaScript 异步编程的基石。它们提供了一种优雅的方式来处理异步操作,易于读写和维护,还可以通过其方法来控制复杂的异步流程。
53 5
|
5月前
|
前端开发
|
6月前
|
前端开发
对Promise的理解
对Promise的理解
42 2
|
6月前
|
前端开发 JavaScript
Promise 详解
Promise 详解
63 0
|
11月前
|
前端开发
Promise
Promise
57 1
|
存储 JSON 前端开发
深入使用 Promise
前面各种铺垫已经好了,现在我们一起来用一用Promise!
73 0
|
前端开发
对promise的理解分享
对promise的理解分享