Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

【JS】题1. async和await #3

Open
Easay opened this issue Mar 30, 2021 · 4 comments
Open

【JS】题1. async和await #3

Easay opened this issue Mar 30, 2021 · 4 comments

Comments

@Easay
Copy link
Owner

Easay commented Mar 30, 2021

两者都是ES7提出的,是基于Promise实现的。通过同步方式的写法,实现异步操作,使代码更易读。async修饰的函数会变成异步函数,返回一个promise对象。当函数执行时,一旦遇到await函数就会先返回一个promise对象,等到异步操作完成,再去执行后面的语句。

await只能放在async函数里,await后面接一个会返回promise对象的函数并执行它。

以下代码输出什么?为什么?

var a = 0
var b = async () => {
  a = a + await 10
  console.log('2', a) // -> ?
}
b()
a++
console.log('1', a) // -> ?

来自:KieSun/all-of-frontend#22

解答:

输出:
1 1
2 10

执行b()时,async返回的是promise对象,直到await之前都是同步执行的,所以b()中执行到a = 0 + await 10,然后执行全局作用域中的a++,a=1。输出1 1,然后再执行b()内部的 a = 0 + 10 = 10,输出 2 10。

若对上述代码稍作修改:

var a = 0
var b = async () => {
    a = await 10 + a
    console.log('2', a) // -> ?
}
b()
a++
console.log('1', a) // -> ?

输出:
1 1
2 11

再对代码进行修改,去掉await

var a = 0
var b = async () => {
  a = a +  10
  console.log('2', a) // -> ?
}
b()
a++
console.log('1', a) // -> ?

输出:
2 10
1 11

@Easay Easay changed the title 题1. async和await 【JS】题1. async和await Apr 1, 2021
@Easay
Copy link
Owner Author

Easay commented May 17, 2021

参考

https://juejin.cn/post/6844904077537574919#heading-33(掘金-霖呆呆)

题目一

async function async1() {
  console.log("async1 start");
  await async2();
  console.log("async1 end");
}
async function async2() {
  console.log("async2");
}
async1();
console.log('start')

结果:

'async1 start'
'async2'
'start'
'async1 end'
  • 先执行async1,遇到await async2后阻塞后面代码的执行,会先去执行同步代码async2,然后跳出async1
  • 执行同步代码start
  • 在一轮宏任务完成后,再执行await后的内容async1 end

可以理解为「紧跟着await后面的语句相当于放到了new Promise中,下一行及之后的语句相当于放在Promise.then中」。

转换后的代码:

async function async1() {
  console.log("async1 start");
  // 原来代码
  // await async2();
  // console.log("async1 end");
  
  // 转换后代码
  new Promise(resolve => {
    console.log("async2")
    resolve()
  }).then(res => console.log("async1 end"))
}
async function async2() {
  console.log("async2");
}
async1();
console.log("start")

题目二

给题目一加定时器:

async function async1() {
  console.log("async1 start");
  await async2();
  console.log("async1 end");
}
async function async2() {
  setTimeout(() => {
    console.log('timer')
  }, 0)
  console.log("async2");
}
async1();
console.log("start")

结果:

'async1 start'
'async2'
'start'
'async1 end'
'timer'

题目三

async function async1() {
  console.log("async1 start");
  await async2();
  console.log("async1 end");
  setTimeout(() => {
    console.log('timer1')
  }, 0)
}
async function async2() {
  setTimeout(() => {
    console.log('timer2')
  }, 0)
  console.log("async2");
}
async1();
setTimeout(() => {
  console.log('timer3')
}, 0)
console.log("start")

结果:

'async1 start'
'async2'
'start'
'async1 end'
'timer2'
'timer3'
'timer1'

题目四

正常情况下,async中的await命令是一个Promise对象,返回该对象的结果。

但如果不是Promise对象的话,就会直接返回对应的值,相当于Promise.resolve()

async function fn () {
  // return await 1234
  // 等同于
  return 123
}
fn().then(res => console.log(res))

结果:

123

题目五

async function async1 () {
  console.log('async1 start');
  await new Promise(resolve => {
    console.log('promise1')
  })
  console.log('async1 success');
  return 'async1 end'
}
console.log('srcipt start')
async1().then(res => console.log(res))
console.log('srcipt end')

在async1中await后面的Promise是没有返回值的,也就是它的状态始终是pending状态,因此相当于一直在await,await,await却始终没有响应...所以在await之后的内容是不会执行的,也包括async1后面的 .then。

结果:

'script start'
'async1 start'
'promise1'
'script end'

题目六

async function async1 () {
  console.log('async1 start');
  await new Promise(resolve => {
    console.log('promise1')
    resolve('promise1 resolve')
  }).then(res => console.log(res))
  console.log('async1 success');
  return 'async1 end'
}
console.log('srcipt start')
async1().then(res => console.log(res))
console.log('srcipt end')

结果:

'script start'
'async1 start'
'promise1'
'script end'
'promise1 resolve'
'async1 success'
'async1 end'

题目七

async function async1 () {
  console.log('async1 start');
  await new Promise(resolve => {
    console.log('promise1')
    resolve('promise resolve')
  })
  console.log('async1 success');
  return 'async1 end'
}
console.log('srcipt start')
async1().then(res => {
  console.log(res)
})
new Promise(resolve => {
  console.log('promise2')
  setTimeout(() => {
    console.log('timer')
  })
})

结果:

srcipt start
async1 start
promise1
promise2
async1 success
async1 end
timer

在async1中的new Promise它的resovle的值和async1().then()里的值是没有关系的。

题目八

async function async1() {
  console.log("async1 start");
  await async2();
  console.log("async1 end");
}

async function async2() {
  console.log("async2");
}

console.log("script start");

setTimeout(function() {
  console.log("setTimeout");
}, 0);

async1();

new Promise(function(resolve) {
  console.log("promise1");
  resolve();
}).then(function() {
  console.log("promise2");
});
console.log('script end')

结果:

script start
async1 start
async2
promise1
script end
async1 end
promise2
setTimeout

题目九

async function testSomething() {
  console.log("执行testSomething");
  return "testSomething";
}

async function testAsync() {
  console.log("执行testAsync");
  return Promise.resolve("hello async");
}

async function test() {
  console.log("test start...");
  const v1 = await testSomething();
  console.log(v1);
  const v2 = await testAsync();
  console.log(v2);
  console.log(v1, v2);
}

test();

var promise = new Promise(resolve => {
  console.log("promise start...");
  resolve("promise");
});
promise.then(val => console.log(val));

console.log("test end...");

结果:

test start...
执行testSomething
promise start...
test end...
testSomething
执行testAsync
promise
hello async
testSomething hello async

@Easay
Copy link
Owner Author

Easay commented May 17, 2021

async处理错误

题目一

async function async1 () {
  await async2();
  console.log('async1');
  return 'async1 success'
}
async function async2 () {
  return new Promise((resolve, reject) => {
    console.log('async2')
    reject('error')
  })
}
async1().then(res => console.log(res))

如果在async函数中抛出了错误,则终止错误结果,不会继续向下执行。

async2
Uncaught (in promise) error

题目二

如果想要使得错误的地方不影响async函数后续的执行的话,可以使用try catch

async function async1() {
  try {
    await Promise.reject('error!!!')
  } catch(e) {
    console.log(e)
  }
  console.log('async1');
  return Promise.resolve('async1 success')
}
async1().then(res => console.log(res))
console.log('script start')

结果:

script start
error!!!
async1
async1 success

@Easay
Copy link
Owner Author

Easay commented May 17, 2021

几道综合题

题目一

const first = () => (new Promise((resolve, reject) => {
    console.log(3);
    let p = new Promise((resolve, reject) => {
        console.log(7);
        setTimeout(() => {
            console.log(5);
            resolve(6);
            console.log(p)
        }, 0)
        resolve(1);
    });
    resolve(2);
    p.then((arg) => {
        console.log(arg);
    });
}));
first().then((arg) => {
    console.log(arg);
});
console.log(4);

结果:

3
7
4
1
2
5
Promise{<resolved>: 1}

题目二

const async1 = async () => {
  console.log('async1');
  setTimeout(() => {
    console.log('timer1')
  }, 2000)
  await new Promise(resolve => {
    console.log('promise1')
  })
  console.log('async1 end')
  return 'async1 success'
} 
console.log('script start');
async1().then(res => console.log(res));
console.log('script end');
Promise.resolve(1)
  .then(2)
  .then(Promise.resolve(3))
  .catch(4)
  .then(res => console.log(res))
setTimeout(() => {
  console.log('timer2')
}, 1000)

结果:

script start
async1
script end
1
timer2
timer1

题目三

const p1 = new Promise((resolve) => {
  setTimeout(() => {
    resolve('resolve3');
    console.log('timer1')
  }, 0)
  resolve('resovle1');
  resolve('resolve2');
}).then(res => {
  console.log(res)
  setTimeout(() => {
    console.log(p1)
  }, 1000)
}).finally(res => {
  console.log('finally', res)
})

结果:

resolve1
finally undefined
timer1
Promise{<resolved>: undefined}
  • Promise的状态一旦改变就无法改变;
  • finally不管Promise的状态是resolved还是rejected都会执行,且它的回调函数是接收不到Promise的结果的,所以finally()中的res是一个迷惑项;
  • 最后一个定时器打印出的p1其实是.finally的返回值,我们知道.finally的返回值如果在没有抛出错误的情况下默认会是上一个Promise的返回值(3.10中也有提到), 而这道题中.finally上一个Promise是.then(),但是这个.then()并没有返回值,所以p1打印出来的Promise的值会是undefined,如果你在定时器的下面加上一个return 1,则值就会变成1

@Easay
Copy link
Owner Author

Easay commented May 26, 2021

面试题

setTimeout(() => {
    console.log(1);
}, 0);
async function main1() {
    new Promise((resolve, reject) => {
        console.log(2);
        resolve();
    }).then(() => {
        console.log(3);
    })
    await main2();
    console.log(7);
}

async function main2() {
    console.log(8);
}

requestAnimationFrame(() => {
    console.log(9);
});
main1();
setTimeout(() => {
    console.log(10);
}, 0);

输出结果:

2 8 3 7 9 1 10

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant