开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 5 天,点击查看活动详情” 异步编程的几种实现方式 依次执行多个异步操作
callback
通过回调函数的方式来规定函数的执行顺序,这种方法无论从可读性还是可维护性出发都不好,不推荐使用
Promise
Promise是一个有状态的对象,抽象的表示了一个异步操作,通过状态来表示异步操作的执行状态
promise基础解决了哪些问题
- 很难向某个操作添加多个回调
promise基础
promise 的状态
- 待定(pending)尚未开始或者正在执行中
- 兑现(fulfilled,有时候也称为“解决”,resolved),表示已经成功完成
- 拒绝(rejected)则表示没有成功完成 状态之间的转换是不可逆的,有两种情况,pending——fulfilled,pending——rejected
promise.then()
- then 方法的参数(
reslove,reject) 当执行了reslove函数,会回调promise对象的.then函数 当执行了reject函数,会回调promise对象的.catche函数 - then 方法的调用:可以调用多次
- then 方法的返回值:一个新的promise对象,可以实现链式调用
Promise 的静态方法
- Promise.resolve(param):返回成功
- Promise.reject(reason):返回失败
- Promise.all([p1,...,pn]):,全部 promise 都是 fulfilled 结果才是 fulfilled 状态;如果有一个失败,结果 promise 就是失败
- Promise.race([p1,...,pn]):结果 promise 的状态跟随第一个变化的 promsie 状态,最先返回 promise 是成功的,结果 promise 就是成功,否则就是失败
- Promise.allSettled([p1,...,pn]):输入一组 promise 返回一个新的 promise,所有的 promise 状态改变后,结果 promise 变成 fulfilled(无论返回的成功与否)
// 考察点.then的链式调用
setTimeout(()=>{
console.log(1)
},0)
let a=new Promise((resolve)=>{
console.log(2)
resolve()
}).then(()=>{
console.log(3)
}).then(()=>{
console.log(4)
})
console.log(5)
2
5
3
4
1
//而Promise的链式调用then,每次都会在内部生成一个新的Promise,然后执行then,在执行的过程中不断向微任务(microtask)推入新的函数,因此直至微任务(microtask)的队列清空后才会执行下一波的macrotask。
async/await
是Generator的语法糖,并对Generator函数进行了改进,完全使用同步的写法去描述异步执行
await
await右边的表达式返回为一个promise时会阻塞代码执行
await规定了异步操作只能一个一个排队执行
// Generator
const gen = function* () {
const f1 = yield readFile('/etc/fstab');
const f2 = yield readFile('/etc/shells');
console.log(f1.toString());
console.log(f2.toString());
};
// async/await
const asyncReadFile = async function () {
const f1 = await readFile('/etc/fstab');
const f2 = await readFile('/etc/shells');
console.log(f1.toString());
console.log(f2.toString());
};
在写法上差别仅存在于使用async对*进行替换,使用await对yield进行替换
async函数对 Generator 函数的改进,体现在以下四点。
- 更好的语义
async和await,比起星号和yield,语义更清楚了。async表示函数里有异步操作,await表示紧跟在后面的表达式需要等待结果。完全使用同步的写法去描述异步执行 - 内置执行器
Generator函数的执行必须依靠执行器,而async函数自带执行器,调用方式跟普通函数的调用一样 - 返回值是 Promise
async函数返回值是 Promise 对象,比 Generator 函数返回的 Iterator 对象方便,可以直接使用then()方法进行调用,async函数必须等到内部所有的await命令的Promise对象执行完,才会发生状态改变。
// async/await 执行逻辑
const asyncReadFile = async function () {
const f1 = await readFile('/etc/fstab');
const f2 = await readFile('/etc/shells');
console.log(f1.toString());
console.log(f2.toString());
};
补充题目
function testSome () {
console.log("执行testSome ");
return "testSome ";
}
async function testAsync() {
console.log("执行testAsync");
return Promise.resolve("hello async");
}
async function test() {
console.log("test start...");
setTimeout(() => {
console.log('setTimeout--1');
});
const v1 = await testSome(); //关键点1
console.log(v1);
const v2 = await testAsync();
console.log(v2);
}
test();
var promise = new Promise((resolve)=> {
console.log("promise start..");
resolve("promise"); //关键点2
});
promise.then((val)=> console.log(val));
console.log("test end...")
// 运行结果
test start...
执行testSome
promise start..
test end...
testSome
执行testAsync
promise
hello async
setTimeout--1
// 在以上执行中宏任务队列都是压在最后执行的