首页 > 解决方案 > Javascript等待/异步执行顺序

问题描述

所以我试图把我的头放在promises/await/async上。我不明白为什么当执行 go() 时,在 console.log(coffee) 之后立即出现带有“finished”的警报。当所有函数都使用等待/承诺时,为什么它只等待 getCoffee() 并且在“完成”警报之后运行其他 axios 调用?

function getCoffee() {
  return new Promise(resolve => {
    setTimeout(() => resolve("☕"), 2000); // it takes 2 seconds to make coffee
  });
}
async function go() {
  try {
    alert("ok");
    const coffee = await getCoffee();

    console.log(coffee); // ☕

    const wes = await axios("https://randomuser.me/api/?results=200");
    console.log("wes"); // using string instead of value for brevity

    const wordPromise = axios("https://randomuser.me/api/?results=200");
    console.log("wordPromise"); // using string instead of value for brevity

    alert("finish");
  } catch (e) {
    console.error(e); // 
  }
}
go();
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.min.js"></script>

标签: javascriptasync-await

解决方案


这里的问题console.log是并不总是像人们想象的那样同步。该规范只要求console.log在开发者控制台中显示一条消息,但对消息的显示方式或时间没有任何要求。根据您的浏览器,结果可能会有所不同,但通常实现如下:

  • 当您console.log对请求进行调用时,会被推送到堆栈上(因此连续调用console.log总是按顺序执行)
  • 在下一个动画帧上,浏览器将尝试处理尽可能多的堆栈(必须处理堆栈中的至少一个元素,因此如果您尝试记录 8 兆字节的数据,浏览器可能会锁定)
  • “处理”堆栈包括将 DOM 元素引用转换为将您带到开发控制台中其他位置的链接、将 JSON 对象转换为可导航和可折叠的 UI 元素或用文本“[Object object]”替换对象
  • 一旦堆栈上的元素被处理,它必须在控制台中呈现。这需要调整控制台的高度,确定是否需要滚动条,确定文本将在哪里换行等。这个过程(在控制台中获取您想要的内容并实际显示在屏幕上)称为“绘画”

因为实际上是这样一个复杂的操作,它可能在语句运行console.log之前执行不完(在某些浏览器中)。alert通过将每次调用替换为alertconsole.log每次调用替换为console.logalert您应该会看到事情实际上是按照预期的顺序执行的。


推荐阅读