异步请求中如何等待结果(第127篇:异步函数(async和await)练习题(异步,消息队列))
好家伙 ,本篇为做题思考
书接上文
题目如下:
1.请给出下列代码的输出结果,并配合"消息队列"写出相关解释
好我们公布答案:
(1) 打印 1;
(2) 调用异步函数 foo();
(3)(在 foo()中)打印 2;
(4)(在 foo()中)await 关键字暂停执行 ,向消息队列中添加一个期约在落定之后执行的任务;
(5) 期约立即落定,把给 await 提供值的任务添加到消息队列;
(6) foo()退出;
(7) 打印 3;
(8) 调用异步函数 bar();
(9)(在 bar()中)打印 4;
(10)(在 bar()中)await 关键字暂停执行 ,为立即可用的值 6 向消息队列中添加一个任务;
(11) bar()退出;
(12) 打印 5;
(13) 顶级线程执行完毕;
(14) JavaScript 运行时从消息队列中取出解决 await 期约的处理程序 ,并将解决的值 8 提供给它;
(15) JavaScript 运行时向消息队列中添加一个恢复执行 foo()函数的任务;
(16) JavaScript 运行时从消息队列中取出恢复执行 bar()的任务及值 6;
(17)(在 bar()中)恢复执行 ,await 取得值 6;
(18)(在 bar()中)打印 6;
(19)(在 bar()中)打印 7;
(20) bar()返回;
(21) 异步任务完成 ,JavaScript 从消息队列中取出恢复执行 foo()的任务及值 8;
(22)(在 foo()中)打印 8;
(23)(在 foo()中)打印 9;
(24) foo()返回 。
所以答案是
1
2
3
4
5
6
7
8
9
好了 ,结束了 ,没什么问题了
步骤也解释清楚了
但是我隐约感到了不对劲
怎么会是123456789呢?
foo()应该是先恢复的,但是这里明显bar()先恢复了
我们上机试一下
诶 ,结果不对
前面地12345都没有问题 ,6789的输出变成了8967
我们主要来看和6789有关的输出字段
我们再来仔细地看看前面地解释 ,并把关键解释划出来
(4)(在 foo()中)await 关键字暂停执行,向消息队列中添加一个期约在落定之后执行的任务;
(5) 期约立即落定 ,把给 await 提供值的任务添加到消息队列;
(6) foo()退出;
(10)(在 bar()中)await 关键字暂停执行 ,为立即可用的值 6 向消息队列中添加一个任务;
(11) bar()退出;
(13) 顶级线程执行完毕;
(14) JavaScript 运行时从消息队列中取出解决 await 期约的处理程序,并将解决的值 8 提供给它;
(15) JavaScript 运行时向消息队列中添加一个恢复执行 foo()函数的任务;
(16) JavaScript 运行时从消息队列中取出恢复执行 bar()的任务及值 6;
我们回顾一下消息队列
一个JavaScript 运行时包含了一个待处理消息的消息队列 。. 每一个消息都关联着一个用以处理这个消息的回调函数 。
再补充一个关于await的知识点
等到 await 右边的值可用了 ,JavaScript 运行时会向消息 队列中推送一个任务 ,这个任务会恢复异步函数的执行 。
我们试着把这个消息队列画出来
(有点抽象,但应该能看懂)
这样 ,我们就会发现 , 因为Promise.resolve(8)被多处理了一次 ,导致了foo()方法后恢复
所以bar()先恢复了
那么实际上机又是怎么回事呢?
(书里面有行小字被我忽略了,后面又找到了)
TC39 对 await 后面是期约的情况如何处理做过一次修改 。修改后 ,本例中的 Promise.resolve(8)只会生成一个 异步任务 。
因此在新版浏览器中 ,这个示例的输出结果为 123458967 。实际开发中 ,对于并行的异步操作我们通常 更关注结果 ,而不依赖执行顺序 。——译者注
实际上机的消息队列
原先的两步处理变成了一步
搞定了,原来如此
创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!