Promise是什么?
Promise
是 JavaScript 中用于处理异步操作的一种机制。它代表了一个尚未完成但预期会在未来某个时间点完成的操作,允许你处理异步操作的结果或者异常。
Promise
的状态
一个 Promise
对象有三种状态:
- Pending(待定): 初始状态,表示异步操作还未完成。
- Fulfilled(已完成): 异步操作成功完成,
Promise
已解决。 - Rejected(已拒绝): 异步操作失败,
Promise
被拒绝。
Promise
的使用
Promise
是通过构造函数创建的,接受一个执行器函数作为参数,执行器函数接收两个参数:resolve
和 reject
。这两个参数是函数,分别用来标记异步操作的成功或失败。
let promise = new Promise(function(resolve, reject) {
let success = true; // 模拟异步操作
if (success) {
resolve("操作成功");
} else {
reject("操作失败");
}
});
then
和 catch
方法
Promise
提供了 .then()
方法来处理成功的结果,.catch()
方法来处理失败的结果。
promise
.then(function(result) {
console.log(result); // 处理成功情况
})
.catch(function(error) {
console.log(error); // 处理失败情况
});
async
和 await
async
和 await
是基于 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 引入了 async
和 await
,使得异步代码看起来像同步代码,进一步提升了可读性。使用 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
对象,避免了回调的嵌套,让代码逻辑更加清晰、易于管理。async
和await
是Promise
的语法糖,进一步简化了异步代码,使得它看起来像同步代码,解决了回调地狱的问题。
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
结果会变成一个对象,包含它的状态(fulfilled
或 rejected
)和结果或原因。此方法无论 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
。如果第一个完成的 Promise
是 fulfilled,则返回的 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
/await
与Promise
配合使用,语法上更加简洁和直观。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
的最终状态。它用于进行最终的清理操作,确保无论成功还是失败都会执行。
- 最新
- 最热
只看作者