理解 promise

71 阅读3分钟

Promise 简介

Promise 是一种用于处理异步操作的编程解决方案,通过链式调用有效地解决了回调地狱的问题,使得异步代码结构更加清晰和可读。Promise 有三种状态:进行中 (Pending)已成功 (Fulfilled)已失败 (Rejected)

  • 当异步操作成功时,Promise 会进入 已成功 状态,使用 .then() 方法处理成功的结果。
  • 当异步操作失败时,Promise 会进入 已失败 状态,使用 .catch() 方法处理错误。

常用方法

  • Promise.all() :接收一个包含多个 Promise 对象的数组,只有当所有 Promise 都成功时才会返回成功结果的数组;如果任意一个 Promise 失败,它会立即失败,并返回失败的原因。
  • Promise.race() :同样接收一个 Promise 对象的数组,只要其中任意一个 Promise 完成(成功或失败),它就会返回该 Promise 的结果或错误。
  • .finally() :无论 Promise 的结果是成功还是失败,都会执行的回调函数。

应用场景

  1. 异步网络请求
    使用 Promise 来处理异步的网络请求,可以更优雅地处理成功和失败的情况。

    function fetchData(url) {
        return new Promise((resolve, reject) => {
            axios.get(url)
                .then(response => resolve(response.data))
                .catch(error => reject('请求失败: ' + error.message));
        });
    }
    
    fetchData('https://jsonplaceholder.typicode.com/users/1')
        .then(data => console.log('数据获取成功:', data))
        .catch(error => console.error('数据获取失败:', error));
    
  2. 替代多层嵌套的回调函数
    使用 Promise 可以将多层嵌套的回调函数转变为链式调用,简化异步代码的结构。

doSomething(function(result) {
doSomethingElse(result, function(newResult) {
 doThirdThing(newResult, function(finalResult) {
   console.log('得到最终结果: ' + finalResult);
 }, failureCallback);
}, failureCallback);
}, failureCallback);

// 该写成 promise 方案,假设每个函数内都实例化了一个 promise 对象
function doSomething() {
return new Promise((resolve, reject) => {
 originalDoSomething(function(result) {
   resolve(result);
 }, function(err) {
   reject(err);
 });
});
}
......
// 现在使用 Promise 链调用
doSomething()
.then(doSomethingElse)
.then(doThirdThing)
.then(finalResult => {
 console.log('得到最终结果: ' + finalResult);
})
.catch(failureCallback);  // 单一的错误处理

  1. 在处理多个请求时,如果希望在某个请求失败时跳过后续的执行,使用 Promise.allSettled()
const requests = [request1, request2, request3];

const promises = requests.map(request => request());

Promise.allSettled(promises).then(results => {
  results.forEach((result, index) => {
    if (result.status === 'fulfilled') {
      console.log(`请求 ${index + 1} 成功:`, result.value);
    } else {
      console.log(`请求 ${index + 1} 失败:`, result.reason);
      // 跳过后续请求的执行逻辑
    }
  });
});

  1. 包装定时器,实现延迟操作
    通过 Promise 包装 setTimeout,可以简化延迟执行的操作。

    function delay(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }
    
    delay(2000).then(() => {
        console.log('2秒后执行');
    });
    

Promise.all 示例

  • Promise.all:处理多个网络请求,当所有请求都成功时才会返回结果。

    function fetchData(url) {
        return new Promise((resolve, reject) => {
            fetch(url)
                .then(response => {
                    if (!response.ok) {
                        reject('网络响应失败');
                    }
                    return response.json();
                })
                .then(data => resolve(data))
                .catch(error => reject('请求失败: ' + error.message));
        });
    }
    
    const user1Promise = fetchData('https://jsonplaceholder.typicode.com/users/1');
    const user2Promise = fetchData('https://jsonplaceholder.typicode.com/users/2');
    
    Promise.all([user1Promise, user2Promise])
        .then(results => {
            console.log('用户1数据:', results[0]);
            console.log('用户2数据:', results[1]);
        })
        .catch(error => console.error('请求失败:', error));
    

封装一个 Promise 类对象

为了更好地理解 Promise 的工作原理,这里封装一个简单的 Promise 类。

class MyPromise {
    constructor(executor) {
        this.state = 'pending';
        this.value = undefined;
        executor(this._resolve.bind(this), this._reject.bind(this));
    }

    _resolve(data) {
        this.state = 'fulfilled';
        this.value = data;
        console.log('完成:', data);
    }

    _reject(reason) {
        this.state = 'rejected';
        this.value = reason;
        console.log('失败:', reason);
    }

    then(onFulfilled, onRejected) {
        if (this.state === 'fulfilled' && onFulfilled) {
            onFulfilled(this.value);
        } else if (this.state === 'rejected' && onRejected) {
            onRejected(this.value);
        }
    }
}

const result = new MyPromise((resolve, reject) => {
    // resolve(5445);
    reject(43434);
});

result.then(
    value => console.log('成功:', value),
    reason => console.log('失败:', reason)
);

console.log(result);