JavaScript Promise

Promise是ES6引入的异步编程解决方案,用于处理异步操作,避免回调地狱问题。Promise表示一个异步操作的最终完成或失败,及其结果值。

Promise的概念

Promise是一个对象,它代表了一个异步操作的最终完成或失败,以及其结果值。Promise有三种状态:

  • pending(进行中):初始状态,既不是成功也不是失败状态
  • fulfilled(已成功):操作成功完成
  • rejected(已失败):操作失败

创建Promise

使用Promise构造函数创建Promise对象,该构造函数接受一个执行器函数作为参数。

// 创建一个简单的Promise
const promise = new Promise((resolve, reject) => {
  // 异步操作
  setTimeout(() => {
    const success = true;
    if (success) {
      resolve('Operation completed successfully!');
    } else {
      reject(new Error('Operation failed!'));
    }
  }, 2000);
});

// 处理Promise结果
promise
  .then(result => {
    console.log('Success:', result);
  })
  .catch(error => {
    console.error('Error:', error.message);
  });

Promise链式调用

Promise的then方法返回一个新的Promise,可以链式调用多个then方法,避免回调地狱。

// Promise链式调用示例
new Promise((resolve, reject) => {
  resolve(1);
})
  .then(value => {
    console.log(value); // 1
    return value + 1;
  })
  .then(value => {
    console.log(value); // 2
    return value + 1;
  })
  .then(value => {
    console.log(value); // 3
    return value + 1;
  })
  .then(value => {
    console.log(value); // 4
  });

Promise错误处理

使用catch方法处理Promise链中的错误,catch方法可以捕获之前所有Promise的错误。

// Promise错误处理示例
new Promise((resolve, reject) => {
  reject(new Error('Something went wrong!'));
})
  .then(result => {
    console.log('Success:', result); // 不会执行
  })
  .catch(error => {
    console.error('Error:', error.message); // Error: Something went wrong!
  });

// 链式调用中的错误处理
new Promise((resolve, reject) => {
  resolve(1);
})
  .then(value => {
    throw new Error('Error in then');
    return value + 1;
  })
  .then(value => {
    console.log(value); // 不会执行
  })
  .catch(error => {
    console.error('Caught error:', error.message); // Caught error: Error in then
  });

Promise.all方法

Promise.all方法接收一个Promise数组,当所有Promise都成功时返回包含所有结果的数组,当有一个Promise失败时返回该失败的Promise。

// Promise.all示例
const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, 'foo');
});

Promise.all([promise1, promise2, promise3])
  .then(values => {
    console.log(values); // [3, 42, 'foo']
  })
  .catch(error => {
    console.error(error);
  });

Promise.race方法

Promise.race方法接收一个Promise数组,返回第一个完成的Promise的结果,无论成功或失败。

// Promise.race示例
const promise1 = new Promise((resolve, reject) => {
  setTimeout(resolve, 500, 'one');
});

const promise2 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, 'two');
});

Promise.race([promise1, promise2])
  .then(value => {
    console.log(value); // two,因为promise2更快完成
  })
  .catch(error => {
    console.error(error);
  });

Promise.resolve和Promise.reject

Promise.resolve方法返回一个已成功的Promise,Promise.reject方法返回一个已失败的Promise。

// Promise.resolve示例
Promise.resolve('Success')
  .then(result => {
    console.log(result); // Success
  });

// Promise.reject示例
Promise.reject(new Error('Failure'))
  .catch(error => {
    console.error(error.message); // Failure
  });

Promise与回调函数的比较

回调函数的问题

  • 回调地狱,代码嵌套过深
  • 错误处理复杂
  • 难以阅读和维护

Promise的优势

  • 链式调用,代码结构清晰
  • 集中错误处理
  • 更好的可读性和可维护性
  • 支持并行操作

示例:使用Promise处理AJAX请求

// 使用Promise封装XMLHttpRequest
function fetchData(url) {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    
    xhr.open('GET', url, true);
    
    xhr.onload = function() {
      if (xhr.status >= 200 && xhr.status < 300) {
        resolve(xhr.responseText);
      } else {
        reject(new Error(xhr.statusText));
      }
    };
    
    xhr.onerror = function() {
      reject(new Error('Network error'));
    };
    
    xhr.send();
  });
}

// 使用Promise发送AJAX请求
fetchData('https://api.example.com/data')
  .then(data => {
    console.log('Data received:', data);
    return fetchData('https://api.example.com/another-data');
  })
  .then(anotherData => {
    console.log('Another data received:', anotherData);
  })
  .catch(error => {
    console.error('Error:', error.message);
  });

Promise的最佳实践

  1. 始终返回Promise,以便进行链式调用
  2. 正确处理错误,使用catch方法
  3. 避免嵌套Promise,使用链式调用
  4. 使用Promise.all处理并行操作
  5. 考虑使用async/await语法,使代码更简洁
« 上一篇 JavaScript回调函数 下一篇 » JavaScript对象