Promise 是 JavaScript 中一种用于处理异步操作的对象,它可以让我们更优雅地处理异步代码,并解决了回调地狱(callback hell)的问题。Promise 是一个代表了异步操作最终完成或失败的对象,并可以获取异步操作的结果。
Promise 的原理是基于状态(state)和回调函数(callback)的机制:
-
状态:Promise 有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。初始状态是 pending,当异步操作完成后,可以变为 fulfilled(成功)或 rejected(失败),一旦状态发生变化,就不可再改变。
-
回调函数:Promise 实例有两个回调函数:成功时的回调函数
then
和失败时的回调函数catch
。当异步操作成功时,会调用then
方法指定的回调函数,传递成功的结果;当异步操作失败时,会调用catch
方法指定的回调函数,传递失败的原因。
下面是一个简单的 Promise 示例:
// 异步操作函数
function asyncOperation() {
return new Promise((resolve, reject) => {
// 模拟异步操作
setTimeout(() => {
const random = Math.random();
if (random < 0.5) {
resolve("Success: " + random);
} else {
reject("Error: " + random);
}
}, 1000);
});
}
// 调用异步操作函数
asyncOperation()
.then((result) => {
console.log(result); // 输出成功结果
})
.catch((error) => {
console.error(error); // 输出失败原因
});
在这个示例中,asyncOperation
函数返回一个 Promise 对象,当异步操作完成后,根据结果调用 resolve
或 reject
。然后我们通过 then
方法来处理成功的结果,通过 catch
方法来处理失败的原因。
Promise 的应用包括但不限于:
- 异步操作:Promise 可以处理异步代码,让代码更具可读性和可维护性。
- 多个异步操作的并行执行和串行执行:通过 Promise 的链式调用和
Promise.all
、Promise.race
方法可以实现多个异步操作的并行执行或串行执行。 - 解决回调地狱:Promise 可以避免回调地狱,使代码结构更清晰、简洁。
- 资源加载和错误处理:Promise 可以用于异步加载资源(例如图片、脚本等)以及错误处理。
Promise 对象有一些常用的静态方法,可以用于处理多个 Promise 实例,或者用于生成新的 Promise 实例。以下是一些常用的 Promise 静态方法:
1. Promise.all(iterable)
Promise.all
方法接收一个可迭代的对象(通常是一个数组),并返回一个新的 Promise 实例。该 Promise 实例在可迭代对象中所有的 Promise 实例都已解析(resolved)或其中任何一个 Promise 实例被拒绝(rejected)时才会解析或拒绝。
const promise1 = Promise.resolve(1);
const promise2 = Promise.resolve(2);
const promise3 = Promise.resolve(3);
Promise.all([promise1, promise2, promise3])
.then(values => {
console.log(values); // 输出:[1, 2, 3]
});
2. Promise.race(iterable)
Promise.race
方法同样接收一个可迭代的对象,并返回一个新的 Promise 实例。该 Promise 实例解析或拒绝,取决于可迭代对象中第一个解析或拒绝的 Promise 实例。
const promise1 = new Promise(resolve => setTimeout(resolve, 100, 'one'));
const promise2 = new Promise(resolve => setTimeout(resolve, 200, 'two'));
Promise.race([promise1, promise2])
.then(value => {
console.log(value); // 输出:'one'
});
3. Promise.resolve(value)
Promise.resolve
方法返回一个已解析的 Promise 实例,根据提供的值。如果提供的值是一个 Promise,则返回该 Promise 实例;如果提供的是一个 thenable 对象(拥有 then 方法的对象),则返回一个新的 Promise 实例,该实例的状态会根据 thenable 对象的状态而变化;其他情况下,返回一个以提供的值解析为成功状态的 Promise 实例。
const promise = Promise.resolve('Success');
promise.then(value => {
console.log(value); // 输出:'Success'
});
4. Promise.reject(reason)
Promise.reject
方法返回一个被拒绝的 Promise 实例,给定一个拒绝原因(通常是一个 Error 对象)。
const reason = new Error('Something went wrong');
const promise = Promise.reject(reason);
promise.catch(error => {
console.error(error.message); // 输出:'Something went wrong'
});
总结:promise的静态方法,all和any的用法区别:
Promise.all(),返回全部promise的返回值,有一个reject就不返回,也就是有一个拒绝就拒绝。
Promise.any(),返回单个promise,第一个resolve的值,所有都拒绝时才会都拒绝。
以下是一些与 Promise 相关的常见笔试题:
1. 理解 Promise 状态变化:
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Success");
}, 1000);
});
console.log(promise); // 输出什么?
2. 使用 Promise 处理异步操作:
function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Data fetched successfully");
}, 2000);
});
}
fetchData().then((data) => {
console.log(data); // 输出什么?
});
3. 处理 Promise 的错误:
function asyncOperation() {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject("Error occurred");
}, 1000);
});
}
asyncOperation().then((result) => {
console.log(result);
}).catch((error) => {
console.error(error); // 输出什么?
});
4. 处理多个 Promise 的并行执行:
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Promise 1 resolved");
}, 1000);
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Promise 2 resolved");
}, 2000);
});
Promise.all([promise1, promise2]).then((values) => {
console.log(values); // 输出什么?
});
5. Promise 的链式调用:
function asyncOperation() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Async operation completed");
}, 1000);
});
}
asyncOperation().then((result) => {
console.log(result); // 输出什么?
return "Next operation";
}).then((result) => {
console.log(result); // 输出什么?
});
以上是一些常见的 Promise 相关的笔试题,通过理解和回答这些题目,可以加深对 Promise 的理解和应用。接下来稍微加点难度,继续做以下笔试题,
//1.同时调用resolve和reject会怎么样?
const promise = new Promise((resolve, reject) => {
resolve();
reject();
});
//正确答案是fullfilled状态。promise一旦从pending状态转换到另一种状态就不可以再改变了,因此示例中
//先被转换成了fullfilled状态,再调用reject就不会被更改为reject状态了。
//2.promise数组串行执行
//用await
const requestAry = [() => api.request1(), () => api.request2(), () => api.request3()];
for (const requestItem of requestAry) {
await requestItem();
}
//用then函数来串联多个promise
const finallyPromise = requestAry.reduce(
(currentPromise, nextRequest) => currentPromise.then(() => nextRequest()),
Promise.resolve() // 创建一个初始promise,用于链接数组内的promise
);
Promise.resolve().then(() => {
console.log(1);
});
await console.log(3);
console.log(2);
//输出:3 1 2
//promise的then的第二个回调函数和catch在请求出错时都会被触发,
//咋一看没什么区别啊,但其实,前者不能捕获当前then第一个回调函数中抛出的错误,但catch可以。
Promise.resolve().then(
() => {
throw new Error('来自成功回调的错误');
},
() => {
// 不会被执行
}
).catch(reason => {
console.log(reason.message); // 将打印出"来自成功回调的错误"
});
//then/catch/finally三个函数都会返回一个新的promise包装对象,
//被包装的值为被执行的回调函数的返回值,回调函数抛出错误则会包装一个rejected状态的promise。
// then函数
Promise.resolve().then(() => 1); // 返回值为 new Promise(resolve => resolve(1))
Promise.resolve().then(() => Promise.resolve(2)); // 返回 new Promise(resolve => resolve(Promise.resolve(2)))
Promise.resolve().then(() => {
throw new Error('abc')
}); // 返回 new Promise(resolve => resolve(Promise.reject(new Error('abc'))))
Promise.reject().then(() => 1, () => 2); // 返回值为 new Promise(resolve => resolve(2))
// catch函数
Promise.reject().catch(() => 3); // 返回值为 new Promise(resolve => resolve(3))
Promise.resolve().catch(() => 4); // 返回值为 new Promise(resolve => resolve(调用catch的promise对象))
// finally函数
// 以下返回值均为 new Promise(resolve => resolve(调用finally的promise对象))
Promise.resolve().finally(() => {});
Promise.reject().finally(() => {});
//promise实现koa2洋葱中间件模型,
//可以让你的请求像剥洋葱一样,一层层进入再反向一层层出来,从而实现对请求统一的前后置处理。
const app = new Koa();
app.use(async (ctx, next) => {
console.log('a-start');
await next();
console.log('a-end');
});
app.use(async (ctx, next) => {
console.log('b-start');
await next();
console.log('b-end');
});
app.listen(3000);
//a-start -> b-start -> b-end -> a-end
请写出下面代码的运行结果,考察promise的执行顺序
const promise4 = new Promise((resolve, reject) => {
Math.random() > 0.5 ? resolve(1) : reject(-1);
}).then(
res => console.log(res),
err => console.log(err),
)
try{
const promise3 = new Promise((resolve, reject) => {
reject(-1);
}).then(
res => console.log(res.a.a,'res')
).catch(e=>{
console.log(res.a,'res')
console.log(333333)
})
}catch(e){
console.log(222222)
}
const promise2 = new Promise((resolve,reject)=>{
resolve('2222')
reject('666')
throw error('throw')
console.log('33333')
}).then(res=>{
throw error('throw')
console.log('then')
}).then(res=>{
console.log(9999)
})
.catch(e=>{
console.log('catch')
}).finally(e=>{
console.log(0)
})
const promise2222 = new Promise((resolve,reject)=>{
resolve(2)
console.log('33333')
}).then(res=>{
throw error('throw')
console.log('then')
}).then(res=>{
console.log(9999)
}).catch(e=>{
console.log('catch')
}).finally(e=>{
console.log(0)
})
手写一个promise-retry
Promise.prototype.retry = function(cb,time){
return new Promise((resolve,reject)=>{
cb().then(res=>{
resolve(res)
}).catch(err=>{
if(time>0){
return Promise.retry(cb,time--)
}else{
reject('重试完毕,依然失败')
}
})
})
}
最后也是全文最重要的,码字不易,欢迎点赞收藏加关注,你的鼓励,是我码字的动力,感谢感谢感谢!!!