你真的弄懂了使用ES6 Promise的不同情况的返回值是什么吗?

Promise是什么?

Promise 是 JavaScript 中用于处理异步操作的一种机制。它代表了一个尚未完成但预期会在未来某个时间点完成的操作,允许你处理异步操作的结果或者异常。

Promise 的状态

一个 Promise 对象有三种状态:

  1. Pending(待定): 初始状态,表示异步操作还未完成。
  2. Fulfilled(已完成): 异步操作成功完成,Promise 已解决。
  3. Rejected(已拒绝): 异步操作失败,Promise 被拒绝。

Promise 的使用

Promise 是通过构造函数创建的,接受一个执行器函数作为参数,执行器函数接收两个参数:resolvereject。这两个参数是函数,分别用来标记异步操作的成功或失败。

let promise = new Promise(function(resolve, reject) {
    let success = true; // 模拟异步操作
    if (success) {
        resolve("操作成功");
    } else {
        reject("操作失败");
    }
});

thencatch 方法

Promise 提供了 .then() 方法来处理成功的结果,.catch() 方法来处理失败的结果。

promise
    .then(function(result) {
        console.log(result); // 处理成功情况
    })
    .catch(function(error) {
        console.log(error); // 处理失败情况
    });

asyncawait

asyncawait 是基于 Promise 的语法糖,它使得异步代码看起来像同步代码,增强了可读性。

async function fetchData() {
    try {
        let result = await promise;
        console.log(result); // 处理成功结果
    } catch (error) {
        console.log(error); // 处理失败
    }
}

链式调用

Promise 可以链式调用,每个 then() 返回一个新的 Promise,允许你继续处理下一个异步操作。这是 Promise 比回调函数更有优势的地方,避免了“回调地狱”的问题。

什么是回调地狱?

在js 中,回调函数常用于处理异步操作。回调函数会在某个操作完成时被调用。如果有多个异步操作需要按顺序执行,你通常需要将一个回调函数嵌套在另一个回调函数内部,这样就会形成“回调嵌套”的结构。随着异步操作增多,代码层级会逐渐加深,导致代码难以理解和维护,这就是所谓的“回调地狱”。

例如,假设你有三个需要顺序执行的异步操作(比如读取文件、请求数据和更新页面),你会这样写:

// 模拟三个异步操作:读取文件、请求数据、更新页面
readFile('file.txt', function(err, data) {
    if (err) {
        console.error('读取文件失败');
    } else {
        requestData(data, function(err, response) {
            if (err) {
                console.error('请求数据失败');
            } else {
                updatePage(response, function(err) {
                    if (err) {
                        console.error('更新页面失败');
                    } else {
                        console.log('页面更新成功');
                    }
                });
            }
        });
    }
});

这个代码的劣势:

  • 逻辑难以理解:业务逻辑分散在多个嵌套的回调函数中,难以清楚地理解每个操作的顺序和流程。
  • 深层嵌套:随着异步操作增多,代码嵌套层级会非常深,导致代码可读性差,调试也变得困难。
  • 错误处理复杂:每个回调函数都需要单独处理错误,这会导致冗余的错误检查代码。

回调地狱的后果

  • 可读性差:代码层级过深,业务逻辑不容易理解。
  • 维护困难:新增或修改功能时,容易出错并影响到其他部分。
  • 错误难以管理:每一层的回调都需要单独处理错误,增加了复杂性。

如何解决回调地狱?——使用 Promise 和链式调用

Promise 和链式调用的引入解决了回调地狱的问题。Promise 使得异步操作变得更加线性和可管理,避免了多层嵌套。

Promise 的链式调用

通过 Promise,你可以将多个异步操作按顺序连接起来,形成一个清晰的链式结构,而不需要嵌套回调函数。

readFile('file.txt')
    .then(function(data) {
        return requestData(data);  // 处理读取的文件数据并返回另一个 Promise
    })
    .then(function(response) {
        return updatePage(response);  // 处理请求的数据并返回另一个 Promise
    })
    .then(function() {
        console.log('页面更新成功');
    })
    .catch(function(err) {
        console.error('出现错误:', err);
    });

这个代码的优势:

  • 扁平化结构:每个操作都在同一个层级,不再有深层嵌套,逻辑更加清晰。
  • 错误处理集中:所有的错误都可以在最后的 catch 中集中处理,减少冗余的错误检查代码。
  • 可读性强:每个步骤的结果通过 then() 返回,整个流程的逻辑一目了然。

    async / await 和更简洁的异步操作

    除了 Promise,JavaScript 引入了 asyncawait,使得异步代码看起来像同步代码,进一步提升了可读性。使用 async/await,你可以避免回调地狱的嵌套,并且处理错误变得更加简洁。

    async function update() {
        try {
            let data = await readFile('file.txt');
            let response = await requestData(data);
            await updatePage(response);
            console.log('页面更新成功');
        } catch (err) {
            console.error('出现错误:', err);
        }
    }
    
    update();
    

    总结

    • 回调地狱 是指在多个异步操作中,回调函数不断嵌套,导致代码结构混乱、可读性差、错误处理复杂的现象。
    • Promise 和链式调用 通过返回 Promise 对象,避免了回调的嵌套,让代码逻辑更加清晰、易于管理。
    • asyncawaitPromise 的语法糖,进一步简化了异步代码,使得它看起来像同步代码,解决了回调地狱的问题。

    Promise怎么用?有哪些方法?

    主要方法:

    • Promise.resolve(value):返回一个已解决的 Promise,如果是 Promise 则返回原 Promise
    • Promise.reject(reason):返回一个已拒绝的 Promise
    • Promise.all(iterable):返回一个新的 Promise,等所有 Promise 成功时触发。
    • Promise.allSettled(iterable):等待所有 Promise 执行完,并返回每个 Promise 的状态。
    • Promise.race(iterable):返回第一个完成的 Promise
    • Promise.any(iterable):返回第一个成功的 Promise,如果所有 Promise 都失败则返回 AggregateError
    • Promise.finally(onFinally):无论 Promise 成功或失败,都会执行 finally 中的操作。

    1. Promise.resolve(value)

    返回一个 已解决(fulfilled) 状态的 Promise 对象。如果传入的值是一个 Promise 对象,则返回该 Promise 对象;如果值是一个普通值,则返回一个 Promise 对象,状态为 fulfilled,且其值为该普通值。

    Promise.resolve(42).then(value => console.log(value)); // 输出 42
    

    如果传入的是一个Promise:

    const p = Promise.resolve(Promise.resolve(42));
    p.then(value => console.log(value)); // 输出 42
    

    2. Promise.reject(reason)

    返回一个 已拒绝(rejected) 状态的 Promise 对象,拒绝的原因是 reason

    Promise.reject('发生错误').catch(error => console.error(error)); // 输出 '发生错误'
    

    3. Promise.all(iterable)

    接收一个 可迭代对象(例如数组),它包含多个 Promise 对象。Promise.all() 返回一个新的 Promise,该 Promise 只有在所有传入的 Promise 都成功时才会变为 fulfilled,并且返回一个包含所有 Promise 结果的数组。如果有任何一个 Promise 失败,返回的 Promise 会立即变为 rejected

    const p1 = Promise.resolve(1);
    const p2 = Promise.resolve(2);
    const p3 = Promise.resolve(3);
    
    Promise.all([p1, p2, p3]).then(values => console.log(values)); // 输出: [1, 2, 3]
    

    4. Promise.allSettled(iterable)

    返回一个新的 Promise,它的状态由所有输入的 Promise 的最终状态决定。每个输入的 Promise 结果会变成一个对象,包含它的状态(fulfilledrejected)和结果或原因。此方法无论 Promise 是成功还是失败都会执行。

    const p1 = Promise.resolve(1);
    const p2 = Promise.reject('error');
    const p3 = Promise.resolve(3);
    
    Promise.allSettled([p1, p2, p3]).then(results => {
      console.log(results);
      // 输出:
      // [
      //   { status: 'fulfilled', value: 1 },
      //   { status: 'rejected', reason: 'error' },
      //   { status: 'fulfilled', value: 3 }
      // ]
    });

    5. Promise.race(iterable)

    返回一个新的 Promise,它的状态取决于第一个完成的 Promise。如果第一个完成的 Promisefulfilled,则返回的 Promise 会变为 fulfilled,并且值为该 Promise 的结果。如果第一个完成的是 rejected,则返回的 Promise 会变为 rejected,并且拒绝的原因是该 Promise 的拒绝原因。

    const p1 = new Promise(resolve => setTimeout(resolve, 100, 'first'));
    const p2 = new Promise(resolve => setTimeout(resolve, 50, 'second'));
    
    Promise.race([p1, p2]).then(result => console.log(result)); // 输出: second
    

    6. Promise.any(iterable)

    返回一个新的 Promise,它的状态为 fulfilled,如果 任何一个 输入的 Promise 成功,返回成功的值。如果所有的 Promise 都失败,则返回一个 AggregateError(即所有 Promise 的错误被汇总)。

    const p1 = Promise.reject('错误1');
    const p2 = Promise.resolve('成功');
    const p3 = Promise.reject('错误2');
    
    Promise.any([p1, p2, p3]).then(result => console.log(result)); // 输出: 成功
    

    7. Promise.finally(onFinally)

    无论 Promise 是成功还是失败,都会执行 finally 中的回调函数。finally 会返回一个 Promise,它会继承前一个 Promise 的状态。如果 finally 中的回调函数返回一个 Promise,则该 Promise 会等待该 Promise 执行完成后返回。

    Promise.resolve('成功')
      .then(value => {
        console.log(value); // 输出: 成功
        return value;
      })
      .finally(() => {
        console.log('清理操作');
      });
    

    8. Promise.all([promise1, promise2, ...])Promise.race([promise1, promise2, ...]) 的区别

    • Promise.all:必须等待所有的 Promise 完成,如果其中任何一个 Promise 被拒绝,整个 Promise 会被拒绝。
    • Promise.race:返回的是 第一个完成的 Promise(无论是成功还是失败),不会等待其他 Promise

    9. Promise.reject()throw 的区别

    • Promise.reject():返回一个 rejected 状态的 Promise,用于明确创建一个失败的 Promise
    • throw:抛出一个错误,通常会被 catch() 捕获,用于同步错误处理。
    // 使用 Promise.reject()
    Promise.reject('错误').catch(e => console.error(e)); // 输出 '错误'
    
    // 使用 throw
    try {
      throw '错误';
    } catch (e) {
      console.error(e); // 输出 '错误'
    }
    

    常见组合方法

    • async/awaitPromise 配合使用,语法上更加简洁和直观。async 函数总是返回一个 Promise,并且 await 会等待 Promise 完成(无论是成功还是失败)。
    async function fetchData() {
      try {
        const response = await fetch('https://api.example.com/data');
        const data = await response.json();
        return data;
      } catch (error) {
        throw new Error('数据加载失败');
      }
    }
    

    使用Promise的不同情况的返回值是什么?

    返回值为 fulfilled 状态的 Promise

    • Promise.resolve():包装一个值,返回 fulfilled 状态的 Promise
    • 普通值返回:如果 .then().catch() 返回普通值,它会被包装成 fulfilled 状态的 Promise

    返回值为 rejected 状态的 Promise

    • Promise.reject():返回一个拒绝状态的 Promise
    • 错误或异常抛出:在 catch() 中抛出异常或返回 Promise.reject(),可以将 Promise 设置为 rejected 状态。

    catch() 返回值

    • 默认返回一个 fulfilled 状态的 Promise,除非你在 catch() 内抛出错误或返回 Promise.reject()

    finally() 返回值

    • 返回值不会改变 Promise 的最终状态。它用于进行最终的清理操作,确保无论成功还是失败都会执行。
    © 版权声明
    THE END
    喜欢就支持一下吧
    点赞14 分享
    评论 共1条

    请登录后发表评论