• 我对Promise 和异步回调的理解在哪个环节出错了?
  • 发布于 2个月前
  • 79 热度
    6 评论
我理解的是:下面的代码会先打印123456,然后执行myfunc1函数的计算步骤,最后等待执行完毕后打印my func1。理论上主线程会先将myfunc1加入到 Promise 队列中,然后直接执行console.log(123456),最后再逐步清空任务队列、即执行myfunc1函数内 Promise 中的计算步骤。

而实际上是:先执行myfunc1函数的计算步骤,执行完毕后打印123456,最后再打印my func1。

哪里没理解对呢?
function myfunc1(){
    return new Promise((resolve,rejects)=>{
        /*这一段是计算步骤开始*/
        let i =1
        for (let index = 1; index < 100000000; index++) {
            i = 1
            for (let index_j = 1; index_j < 100; index_j++) {
                i *=index_j
            }
        }
        /*这一段是计算步骤结束*/
        resolve("my func1")
    })
}
myfunc1()
.then(result=>{
    console.log(result)
})
console.log(123456)

用户评论
  • 强势控局
  • JavaScript 在浏览器上,不使用 WebWorker 的情况下,并没有真正意义的并行执行,只不过是一堆后续操作和一堆任务及其逻辑依赖顺序罢了。
  • 2024/4/7 21:24:00 [ 0 ] [ 0 ] 回复
  • 别来无恙
  • 我来盲猜一下。
    你以为 Promise 跑程序就像 Promise 跑 AJAX 一样是异步的,因为跑 AJAX 的时候,是先执行了后面的代码,再在 AJAX 收到回复以后异步执行 then()的内容。
    但这个的异步是来自 AJAX (Asynchronous JavaScript and XML)里的 Asynchronous 而不是来自 Promise 。不管你用的是不是 Promise ,用 AJAX 就是异步的,不使用 AJAX 的代码默认就是同步的。

    同理 setTimeout 也是一个异步功能,不管你用不用 Promise 他都是异步的。


    换一种说法,不管是 Promise 也好 await 也好,要实现异步执行,必须要用异步执行功能。不管是 AJAX 也好,还是 setTimeout 也好,用了这些,你的程序才能异步起来,然后 Promise 也好 await 也好,才能用上异步执行功能。如果你的代码本来就是同步的,那你写 Promise 或者 await 都是白写,因为没有异步代码可以给你 await 。

  • 2024/4/7 21:22:00 [ 0 ] [ 0 ] 回复
  • 蹦跶少年
  • 解释执行顺序如下:
    调用 myfunc1():

    函数 myfunc1() 被调用,它立即返回一个 Promise 对象。这个 Promise 对象会立即开始执行其内部的构造函数提供的异步任务。
    执行 Promise 构造函数中的异步任务:

    异步任务(即传给 Promise 构造函数的回调函数)开始执行。这里,该任务包含两个嵌套的循环,进行大量的计算工作。
    计算过程中,控制台不会有任何输出,因为所有操作都在内存中进行,且由于计算量大,这部分可能耗时较长。
    当计算步骤全部完成(即所有循环迭代结束),resolve("my func1") 被调用,将字符串 "my func1" 作为成功的结果传递给 Promise 链。
    同步代码继续执行:
    在 myfunc1() 返回 Promise 并开始执行异步任务后,JavaScript 引擎继续执行后面的同步代码。
    下一行是 console.log(123456),因此立即输出数字 123456 到控制台。
    微任务检查点:
    当当前执行上下文(如事件循环的一个宏任务)中的所有同步代码执行完毕后,事件循环到达一个检查点,此时会处理待处理的微任务队列。
    由于 myfunc1() 返回的 Promise 在之前已执行 resolve(),对应的 .then() 方法被注册为一个微任务,等待执行。
    执行 .then() 中的回调:

    微任务队列中的第一个任务就是之前注册的 .then() 回调,该回调函数接收 result 参数(即 "my func1")并执行 console.log(result)。
    控制台输出字符串 "my func1",这是整个程序中的最后一个操作。
    综上所述,代码的执行顺序是:

    创建并开始执行 Promise ,其中包含大量计算。
    同步输出 123456 到控制台。
    计算完成后,Promise 解决,将 "my func1" 放入微任务队列。
    事件循环处理微任务,执行 .then() 回调,输出 "my func1" 到控制台。
    所以,最终在控制台看到的输出顺序是:
    // 123456
    // my func1
  • 2024/4/7 21:21:00 [ 0 ] [ 0 ] 回复
  • 浅歌
  • lz 对 js promises 和 js 的异步的理解有误。Promise 的异步本质是回调函数,以前 js 没有 Promise 的时候,js 和 Python 这些脚本一样,要实现异步只有用回调函数( callback function )来实现,结果就是导致回调地狱的出现。后来为了解决这个问题才有了 Promise ,但 Promise 本质上还是更好用的回调函数,并没有改变任何 js 的底层。然后 async await 是 Promise 的语法糖,async await 的代码看起来像是同步,实际上依旧是同步执行的回调

    so ,js 中并不存在语言或者 js 引擎层面的任务排队这个概念,他就是一路同步执行下去的。然后 Peomis 构造函数是立刻执行,所以你在构造函数里做大量计算,这种会一直占用线程的操作的话,后面的操作自然不会去执行了!!
  • 2024/4/7 21:19:00 [ 0 ] [ 0 ] 回复
  • 余归
  • Promise 构造函数是同步执行,后往 micro task queue 里加 then 中的函数,接着继续执行剩余的同步代码,等执行栈空了,再从队列中取出任务进到执行栈中,输出 my func1
  • 2024/4/7 21:19:00 [ 0 ] [ 0 ] 回复
  • 褪色时间
  • 因为你的 Promise 函数里并没有微任务或类似 setTimeout 的事件循环任务,你把计算步骤放到 setTimeout(func, 0) 或者 queueMicrotask 里再试试。
  • 2024/4/7 21:18:00 [ 0 ] [ 0 ] 回复