面试题
阅读下面代码,分析浏览器环境下的执行结果,并说明具体原因。
async function async1() {
console.log("AAAA");
async2();
console.log("BBBB");
}
async function async2() {
console.log("CCCC");
}
console.log("DDDD");
setTimeout(function () {
console.log("FFFF");
}, 0);
async1();
new Promise(function (resolve) {
console.log("GGGG");
resolve();
}).then(function () {
console.log("HHHH");
});
console.log("IIII");
async2 前加上 await
async function async1() {
console.log("AAAA");
await async2(); // await new Promise(function(resolve) { resulve(undefined) })
console.log("BBBB");
}
async function async2() {
console.log("CCCC");
}
console.log("DDDD");
setTimeout(function () {
console.log("FFFF");
}, 0);
async1();
new Promise(function (resolve) {
console.log("GGGG");
resolve();
}).then(function () {
console.log("HHHH");
});
console.log("IIII");
结果输出是 DDDD AAAA CCCC GGGG IIII BBBB HHHH FFFF
解析
本题考察重点是 js 异步执行、 宏任务、 微任务。
这道题的坑就在于 async 中如果没有 await,那么它就是一个纯同步函数。
这道题的起始代码在第 9 行,输出DDDD
第 10 行计时器开启一个异步任务 t1(一个称呼),这个任务且为宏任务。
第 13 行函数async1
执行,这个函数内没有 await 所以它其实就是一个纯同步函数,打印输出AAAA
,
在async1
中执行async2
函数,因为async2
的内部也没有 await,所以它也是个纯同步函数,打印输出CCCC
紧接着打印输出BBBB
。
第 14 行 new Promise 执行里面的代码也是同步的,所以打印输出GGGG
,resolve()调用的时候开启一个异步任务 t2(一个称呼),且这个任务 t2 是微任务,它的执行交给 then()中的第一个回调函数执行,且优先级高于宏任务(t1)执行。
第 20 行打印输出IIII
,此时线程上的同步任务全部执行结束。
在执行任务队列中的异步任务时,微任务优先于宏任务执行,所以先执行微任务 t2 打印输出 HHHH
,然后执行宏任务 t1 打印输出 FFFF
所以综上 结果输出是 DDDD AAAA CCCC BBBB GGGG IIII HHHH FFFF
面试题2
async function t1() {
let a = await "lagou";
console.log(a);
}
t1();
console.log('a')
先打印A 后执行微任务里的 let a = await “lagou”;
console.log(a);
原理其实就是Generator
问题1解析
await
是一个表达式,如果后面不是一个 promise
对象,会先把表达式转换成promise
function * t1 () {
let a = yield "lagou"
console.log(a)
}
const generator = t1()
let result = generator.next()
result.value = Promise.resolve(result.value)
result.value.then(data => {
generator.next(data)
})
console.log('xx')
function * t1 () {
let a = yield 'lagou'
console.log(a)
}
co(t1)
function co (generator) {
const g = generator()
function handleResult (result) {
if (result.done) {
return Promise.resolve(result.value)
}
// 如果 yield 后面的值不是 Promise 对象,保证成 Promise 对象
if (!(result.value instanceof Promise)) {
result.value = Promise.resolve(result.value)
}
return result.value.then(function (data) {
handleResult(g.next(data))
})
}
return handleResult(g.next())
}
问题 2
async function t2 () {
let a = await new Promise((resolve) => {});
console.log(a); //
}
t2();
问题2解析
await
后面如果跟一个 promise
对象,await
将等待这个 promise
对象的 resolve
状态的值 value
,且将这个值返回给前面的变量,此时的 promise
对象的状态是一个 pending
状态,没有 resolve
状态值,所以什么也打印不了。
function * t2 () {
let a = yield new Promise((resolve) => {});
console.log(a); //
}
const generator = t2()
const result = generator.next()
result.value.then(v => {
generator.next(v)
})
问题 3
async function t3 () {
let a = await new Promise((resolve) => {
resolve();
});
console.log(a);
}
t3();
问题3解析
await
后面如果跟一个 promise
对象,await
将等待这个 promise
对象的 resolve
状态的值 value
,且将这个值返回给前面的变量,此时的 promise
对象的状态是一个 resolve
状态,但是它的状态值是undefined
,所以打印出 undefined
。
function * t3 () {
let a = yield new Promise((resolve) => {
resolve();
});
console.log(a); //undefined
}
const generator = t3()
const result = generator.next()
result.value.then(v => {
generator.next(v)
})
问题 4
async function t4 () {
let a = await new Promise((resolve) => {
resolve("hello");
});
console.log(a);
}
t4();
问题4解析
await
后面如果跟一个 promise
对象,await
将等待这个promise
对象的resolve
状态的值,且将这个值返回给前面的变量,此时的promise
对象的状态是一个 resolve
状态,它的状态值是 hello
,所以打印出 hello
。
function * t4 () {
let a = yield new Promise((resolve) => {
resolve("hello")
})
console.log(a) //hello
}
const generator = t4()
const result = generator.next()
result.value.then(v => {
generator.next(v)
})
问题 5
async function t5() {
let a = await new Promise((resolve) => {
resolve("hello");
}).then(() => {
return "lala";
});
console.log(a); //lala
}
t5();
问题5解析
await
后面如果跟一个promise
对象,await
将等待这个 promise
对象的 resolve
状态的值,且将这个值返回给前面的变量,此时的 promise
对象的状态是一个 resolve
状态,它的状态值是 hello
,紧接着后面又执行了一个 then
方法,then
方法又会返回一个全新的 promise
对象,且这个 then
方法中的返回值会作为这个全新的 promise
中 resolve
的值,所以最终的结果是 lala
。
问题 6
async function t6() {
let a = await fn().then((res) => {
return res;
});
console.log(a);
}
async function fn() {
await new Promise((resolve) => {
resolve("lagou");
});
}
t6();
问题6解析
首先考虑 fn()
执行返回一个promise
对象,因为 fn
执行没有返回值,所以这个 promise
对象的状态 resolve
的值是 undefined
,且将这个 undefined
当作下一个 then
中回调函数的参数,所以打印的结果是 undefined
async function t6() {
let a = await new Promise(function (resolve) {
resolve(undefined)
}).then((res) => {
return res;
});
console.log(a); //undefined
}
问题 7
async function t7() {
let a = await fn().then((res) => {
return res;
});
console.log(a);
}
async function fn() {
await new Promise((resolve) => {
resolve("lagou");
});
return "lala";
}
t7();
问题7解析
首先考虑 fn()
执行返回一个 promise
对象,因为fn()
执行有返回值lala
,所以这个 promise
对象的状态 resolve
的值是 lala
,且将这个 lala
当作下一个 then
中回调函数的参数,所以打印的结果是 lala
。
async function t7() {
let a = await new Promise(function (resolve) {
resolve('lala')
}).then((res) => {
return res;
});
console.log(a); // lala
}
t7();
注意细节
async
函数执行的返回结果是一个promise
对象,这个函数的返回值是这个promise
状态值resolve
的值await
后面如果不是一个promise
对象,将直接返回这个值await
后面如果是一个promise
对象,将会把这个promise
的状态resolve
的值返回出去。- 以上没有考虑
reject
状态。