异步
let a = 0
setTimeout(() => {
a = 1
}, 1000)
console.log(a) // 0
此时这个延迟就成为异步执行的了,a值还没有变1就被使用输出,我们只能得到0。
Promise
有时候我们不得不进行异步操作,比如从后台请求数据,我们需要时间,等待它得到数据后再使用。
Promise基本使用
new Promise()内接收一个函数,入参为resolve, reject
Promise内的函数将可以执行任意时长,执行到调用resolve()或reject(),我们此处把它放在延迟1s后执行,此时a已经被赋值为1,因此就可以得到被赋值后的a。
**resolve()**进入.then也就是执行成功回调,**reject()**进入.catch也就是手动执行错误进入捕获异常,reject()用的较少。
let a = 0
new Promise((resolve, reject) => {
setTimeout(() => {
a = 1
resolve()
}, 1000)
})
.then(() => {
console.log(a) //1
})
.catch(() => {}
)
Promise可进行连续回调
-
第一种方式,回调函数中接受返回一个新的Promise进行下一步回调。
-
第二种方式,Promise.resolve(res)在res为普通数据时等同于new Promise并且resolve(res)
-
第三种也是最常用的,再异步回调中直接返回普通数据也可当作接受了一个新的Promise进行下一步回调
let a = 0
new Promise((resolve, reject) => {
setTimeout(() => {
a = 1
resolve(a)
}, 1000)
})
.then((res) => {
return new Promise((resolve, reject) => {
resolve(res)
})
//等同于
//return Promise.resolve(res)
//等同于
//return res
})
.then((res) => {
console.log(res) //1
})
.catch(() => {})
Promise回调可接受入参
- .then中的回调函数可以存在入参,入参为**resolve()**手动传入,此处res便是传入的a值。
- .catch与reject()的关系与上面两者同理,只不过变成了手动捕捉错误时的回调。
let a = 0
new Promise((resolve, reject) => {
setTimeout(() => {
a = 1
resolve(a)
}, 1000)
})
.then((res) => {
console.log(res) //1
})
.catch(() => {})
Promise.all(promises) ,能够一次并行处理多个 promise,并且只返回一个 promise 实例, 那个输入的所有 promise 的 resolve 回调的结果是一个数组。
1.工作原理
Promise.all() 是一个内置的辅助函数,接受一组 promise(或者一个可迭代的对象),并返回一个promise :
ini复制代码const allPromise = Promise.all([promise1, promise2, …]);
可以使用 then 方法提取第一个 promise 的值:
allPromise.then((values) => {
values; // [valueOfPromise1, valueOfPromise2, ...]
});
也可以使用 async/await 语法:
const values = await allPromise;
console.log(values); // [valueOfPromise1, valueOfPromise2, ...]
Promise.all() 返回的 promise 被解析或拒绝的方式。
如果 allPromise 都被成功解析,那么 allPromise 将使用一个包含各个 promise 已执行完成后的值的数组作为结果。数组中 promise 的顺序是很重要的——将按照这个顺序得到已实现的值。
但是如果至少有一个 promise 被 rejected ,那么 allPromise 会以同样的原因立即 rejected (不等待其他 promise 的执行)。
如果所有的 promise 被 rejected ,等待所有的promise 执行完成,但只会返回最先被rejected 的promise 的 reject 原因。
具体使用可以参考: https://juejin.cn/post/7003713678419705870
Promise.all() 的这种行为被称为快速失败,如果 promise 数组中至少有一个 promise 被 rejected ,那么返回的 promise 也被拒绝。如果promise 数组中所有的都被 rejected ,那么返回的promise 被拒绝的原因是先rejected的那一个。
Promise.all() 是并行执行异步操作并获取所有 resolve 值的最佳方法,非常适合需要同时获取异步操作结果来进行下一步运算的场合
async/await
Promise是用来解决回调地域问题,因此es7出现了async/await,是Promise的语法糖,等同于Promise的链式调用+ Exception处理。
async/await有一个限制就是必须在函数中使用,因此我们将代码包进一个函数,并在函数前加上async,这样我们便可以在函数中使用await关键字。
const test = async () => {
let a = 0
...
}
test()
await用在哪里呢?用在.then回调前的Promise
await后面跟着Promise,而它的返回值便是回调时resolve()传来的值,代替了回调函数,看起来代码一下子就清晰很多了。
const test = async () => {
let a = 0
const res = await new Promise((resolve, reject) => {
setTimeout(() => {
a = 1
resolve(a)
}, 1000)
})
console.log(res) //1
}
test()
CallBack 和Promise之间的区别
两者之间的主要区别在于,使用回调方法时,我们通常只是将回调传递给一个函数,该函数将在完成时被调用以获取某些结果。但是,在Promise中,您将回调附加在返回的Promise对象上。
CallBacks:
function getMoneyBack(money, callback) {
if (typeof money !== 'number') {
callback(null, new Error('money is not a number'))
} else {
callback(money)
}
}
const money = getMoneyBack(1200)
console.log(money)
Promises:
function getMoneyBack(money) {
return new Promise((resolve, reject) => {
if (typeof money !== 'number') {
reject(new Error('money is not a number'))
} else {
resolve(money)
}
})
}
getMoneyBack(1200).then((money) => {
console.log(money)
})
callback 导致的回调地狱
asyncOperation1(function(result1) {
if (result1) {
asyncOperation2(result1, function(result2) {
if (result2) {
asyncOperation3(result2, function(result3) {
if (result3) {
asyncOperation4(result3, function(result4) {
// 处理最终结果
console.log('最终结果处理:', result4);
});
} else {
// 错误处理
console.error('第三步操作失败');
}
});
} else {
// 错误处理
console.error('第二步操作失败');
}
});
} else {
// 错误处理
console.error('第一步操作失败');
}
});
为了解决这个问题,可以使用 Promises 或 async/await 来重构代码,使异步操作更加清晰和易于管理。以下是使用 Promise 重写的上述代码:
function asyncOperation1() {
return new Promise((resolve, reject) => {
// 模拟异步操作
setTimeout(() => {
const result1 = true; // 假设操作成功
result1 ? resolve(result1) : reject('第一步操作失败');
}, 1000);
});
}
// 假设其他操作也返回 Promise
// ...
asyncOperation1()
.then(result1 => {
return asyncOperation2(result1); // 假设返回新的 Promise
})
.then(result2 => {
return asyncOperation3(result2); // 同上
})
.then(result3 => {
return asyncOperation4(result3); // 同上
})
.then(result4 => {
console.log('最终结果处理:', result4);
})
.catch(error => {
console.error('操作失败:', error);
});
使用 Promise,我们创建了一个清晰的执行链,每个 .then() 处理一个步骤的结果,并且 .catch() 用于集中处理所有步骤中可能出现的错误。这样,代码的逻辑更加直观,也更容易维护
总结
-
Promise 是一种更底层的异步编程模型,而 async/await 则是基于 Promise 的语法糖,使异步代码更加清晰易读。
-
在实际使用中,async/await 更容易理解和维护,但它们本质上仍然依赖于 Promise。
参考文档:
- https://juejin.cn/post/7078882164032421924
- https://juejin.cn/post/7003713678419705870
- https://cloud.tencent.com/developer/article/1610004