ES6 Promise:JavaScript异步操作的巅峰之选(二)

212 阅读7分钟

前言

前一篇我们讲到异步编程、回调函数、Promise的基本用法、异步编程的挑战还有Promise的状态转换,今天我们继续细聊Promise的链式调用、错误处理机制还有Promise的高级用法,大家一起充能吧~~

1. Promise的链式调用

1> 使用.then()处理Promise的结果

在Promise的链式调用中,.then()方法用于处理Promise对象成功(Fulfilled)状态时的结果。它接受两个参数,第一个参数是在Promise成功时执行的回调函数,第二个参数是可选的,用于处理可能在回调中抛出的错误。

promise
  .then((result) => {
    // 处理成功的情况
    console.log(result);
  })
  .catch((error) => {
    // 处理可能在回调中抛出的错误
    console.error(error);
  });

多个.then()可以串联,形成Promise链。每个.then()处理上一个Promise的结果,从而使代码更加清晰和可读。

promise
  .then((result1) => {
    console.log(result1);
    return result1 + 10;
  })
  .then((result2) => {
    console.log(result2);
    // 后续操作...
  })
  .catch((error) => {
    console.error(error);
  });

2> .catch()用于捕获错误

.catch()方法用于捕获Promise链中的错误。它接受一个回调函数,该函数处理链中任何Promise被Rejected时抛出的错误。

promise
  .then((result) => {
    // 处理成功的情况
    console.log(result);
  })
  .catch((error) => {
    // 处理链中任何Promise被Rejected时的错误
    console.error(error);
  });

使用.catch()可以更清晰地处理错误,而不必在每个.then()中都进行错误处理。

3> .finally()的作用和用法

.finally()方法用于指定Promise在结束时(无论成功还是失败)都要执行的回调函数。这对于需要在Promise完成后执行一些清理工作的情况很有用。

promise
  .then((result) => {
    // 处理成功的情况
    console.log(result);
  })
  .catch((error) => {
    // 处理错误
    console.error(error);
  })
  .finally(() => {
    // 无论Promise成功还是失败,都会执行这里的回调
    console.log('Promise结束');
  });

.finally()中的回调函数在Promise链结束时都会执行,无论Promise的状态是Fulfilled还是Rejected。

2. Promise的错误处理

1> Promise中的错误处理机制

在Promise中,错误处理主要通过两种机制来实现:

  1. 使用.catch()方法: 通过.catch()方法捕获Promise链中的错误。.catch()接受一个回调函数,该函数会在Promise链中任何Promise被Rejected时执行。

    promise
      .then((result) => {
        // 处理成功的情况
        console.log(result);
      })
      .catch((error) => {
        // 处理链中任何Promise被Rejected时的错误
        console.error(error);
      });
    
  2. 使用.finally()方法: 通过.finally()方法指定在Promise结束时(无论成功还是失败)都要执行的回调函数。这对于清理工作很有用。

    promise
      .then((result) => {
        // 处理成功的情况
        console.log(result);
      })
      .catch((error) => {
        // 处理错误
        console.error(error);
      })
      .finally(() => {
        // 无论Promise成功还是失败,都会执行这里的回调
        console.log('Promise结束');
      });
    

2> 使用.catch().finally()处理错误

.catch().finally()可以结合使用,以更全面地处理Promise的错误情况。

promise
  .then((result) => {
    // 处理成功的情况
    console.log(result);
  })
  .catch((error) => {
    // 处理链中任何Promise被Rejected时的错误
    console.error(error);
  })
  .finally(() => {
    // 无论Promise成功还是失败,都会执行这里的回调
    console.log('Promise结束');
  });

在这个例子中,.catch()捕获任何在Promise链中发生的错误,.finally()中的回调函数会在Promise结束时执行,无论成功还是失败。这样,可以在错误发生时执行错误处理逻辑,并在最终结束时执行清理工作。

3. Promise的实际应用

1> 异步任务中的Promise应用

Promise在异步任务中的应用广泛,以下是一些实际应用的例子:

  1. 网络请求:

    function fetchData() {
      return new Promise((resolve, reject) => {
        // 发起网络请求
        fetch('https://api.example.com/data')
          .then(response => response.json())
          .then(data => resolve(data))
          .catch(error => reject(error));
      });
    }
    
    // 使用
    fetchData()
      .then(result => console.log(result))
      .catch(error => console.error(error));
    
  2. 定时器:

    function delay(time) {
      return new Promise(resolve => {
        setTimeout(() => {
          resolve('Delayed operation completed');
        }, time);
      });
    }
    
    // 使用
    delay(2000)
      .then(result => console.log(result))
      .catch(error => console.error(error));
    
  3. 文件读写:

    function readFile(filePath) {
      return new Promise((resolve, reject) => {
        // 读取文件
        fs.readFile(filePath, 'utf8', (err, data) => {
          if (err) {
            reject(err);
          } else {
            resolve(data);
          }
        });
      });
    }
    
    // 使用
    readFile('example.txt')
      .then(result => console.log(result))
      .catch(error => console.error(error));
    

2> Promise如何改善代码结构

Promise可以改善代码结构,使异步代码更易读、可维护。以下是一些例子:

  1. 回调地狱的解决:

    function fetchData() {
      return new Promise((resolve, reject) => {
        // 异步操作
        fetch('https://api.example.com/data')
          .then(response => response.json())
          .then(data => resolve(data))
          .catch(error => reject(error));
      });
    }
    
    function processData(data) {
      return new Promise((resolve, reject) => {
        // 处理数据
        if (data.valid) {
          resolve('Data is valid');
        } else {
          reject('Invalid data');
        }
      });
    }
    
    // 使用
    fetchData()
      .then(processData)
      .then(result => console.log(result))
      .catch(error => console.error(error));
    

    上述代码避免了传统的回调地狱,通过Promise链实现了清晰的代码流程。

  2. 并发控制:

    const promises = [asyncOperation1(), asyncOperation2(), asyncOperation3()];
    
    Promise.all(promises)
      .then(results => {
        // 处理所有异步操作的结果
        console.log(results);
      })
      .catch(error => {
        // 处理任何一个异步操作的错误
        console.error(error);
      });
    

    使用Promise.all()可以同时处理多个异步操作,等待它们都完成后执行后续操作,从而实现更高效的并发控制。

  3. 清理工作:

    function fetchData() {
      return new Promise((resolve, reject) => {
        // 异步操作
        fetch('https://api.example.com/data')
          .then(response => response.json())
          .then(data => resolve(data))
          .catch(error => reject(error))
          .finally(() => {
            // 清理工作
            console.log('Cleanup after data fetching');
          });
      });
    }
    
    // 使用
    fetchData()
      .then(result => console.log(result))
      .catch(error => console.error(error));
    

    .finally()可以用于指定在Promise结束时执行的清理工作,提高代码的健壮性和可维护性。

通过这些实际应用和改善代码结构的例子,可以看到Promise在处理异步任务时的灵活性和优雅性。这使得代码更易读、易维护,并减少了传统回调风格的一些问题。

4. Promise的高级用法

1> Promise.all(): 处理多个Promise

Promise.all() 方法接受一个Promise数组作为参数,返回一个新的Promise。这个新Promise在数组中所有的Promise都成功完成时才会成功,一旦有一个Promise失败(Rejected),它就会失败。

const promise1 = Promise.resolve('One');
const promise2 = new Promise((resolve, reject) => setTimeout(() => resolve('Two'), 2000));
const promise3 = new Promise((resolve, reject) => setTimeout(() => resolve('Three'), 1000));

Promise.all([promise1, promise2, promise3])
  .then(results => {
    console.log(results); // ['One', 'Two', 'Three']
  })
  .catch(error => {
    console.error(error);
  });

在这个例子中,Promise.all() 等待 promise1promise2promise3 都成功完成,然后返回一个包含所有结果的数组。

2> Promise.race(): 处理多个Promise,只取第一个完成的结果

Promise.race() 方法同样接受一个Promise数组,但它在数组中的任何一个Promise成功或失败时就会立即返回。

const promise1 = new Promise((resolve, reject) => setTimeout(() => resolve('One'), 2000));
const promise2 = new Promise((resolve, reject) => setTimeout(() => resolve('Two'), 1000));

Promise.race([promise1, promise2])
  .then(result => {
    console.log(result); // 'Two',因为它首先完成
  })
  .catch(error => {
    console.error(error);
  });

在这个例子中,Promise.race() 返回的Promise将与第一个完成的Promise具有相同的状态和结果。

3> Promise.resolve()Promise.reject()

  • Promise.resolve(): 返回一个以给定值解析后的Promise对象。如果该值是一个Promise,它将原封不动地返回;如果是一个thenable(具有then方法的对象),返回的Promise会采用其状态。

    const resolvedPromise = Promise.resolve('Resolved Value');
    
    resolvedPromise
      .then(result => {
        console.log(result); // 'Resolved Value'
      });
    
  • Promise.reject(): 返回一个带有拒绝原因的Promise对象。

    const rejectedPromise = Promise.reject('Rejected Reason');
    
    rejectedPromise
      .catch(error => {
        console.error(error); // 'Rejected Reason'
      });
    

这些高级用法扩展了Promise的功能,使其更加灵活和强大。Promise.all()Promise.race() 特别适用于处理多个异步操作,而 Promise.resolve()Promise.reject() 则方便地创建一个已解决或已拒绝的Promise。

4> 使用Promise解决挑战

function task1() {
  return new Promise((resolve, reject) => {
    // 异步操作
    // 如果成功,调用 resolve(result)
    // 如果失败,调用 reject(error)
  });
}

function task2() {
  return new Promise((resolve, reject) => {
    // 异步操作
  });
}

function task3() {
  return new Promise((resolve, reject) => {
    // 异步操作
  });
}

// 使用Promise解决回调地狱
task1()
  .then(result1 => {
    console.log(result1);
    return task2();
  })
  .then(result2 => {
    console.log(result2);
    return task3();
  })
  .then(result3 => {
    console.log(result3);
    // 后续操作...
  })
  .catch(error => {
    console.error(error);
  });

// 使用Promise.all解决并发控制
Promise.all([task1(), task2()])
  .then(([result1, result2]) => {
    console.log(result1, result2);
    return task3();
  })
  .then(result3 => {
    console.log(result3);
    // 后续操作...
  })
  .catch(error => {
    console.error(error);
  });

// 使用Promise进行错误处理
task1()
  .then(result1 => {
    console.log(result1);
    return task2();
  })
  .then(result2 => {
    console.log(result2);
    return task3();
  })
  .then(result3 => {
    console.log(result3);
    // 后续操作...
  })
  .catch(error => {
    console.error(error);
  });

通过使用Promise,我们能够更清晰、更可读地处理异步编程中的挑战,避免了回调地狱,简化了并发控制,同时提供了更优雅的错误处理机制。

结语

那么我们今天的内容就结束啦,欢迎各路大神在评论区讨论~~

点赞收藏不迷路,咱们下期再见ヾ( ̄▽ ̄)ByeBye~