请教 JS 中有关 Promise 和回调函数的写法问题

查看 293|回复 23
作者:wuoty   
在网上浏览的时候看到了下面的一种写法,可以通过新建一个 Promise 对象,在 Promise 对象中绑定回调函数,并获取回调结果,类似与下面这种:
    const img = document.getElementById("bg");
   
    const message = () => {
      return new Promise((resolve, reject) => {
        img.onload = () => {
          resolve("Image loaded successfully"); // 返回回调函数的结果
        };
      });
    };
    const AsyncTest = async () => {
      try {
        const msg = await message();
        console.log(msg);
      } catch (error) {
        console.log(error);
      }
    };
上面的代码确实能够将回调函数的返回值作为 Promise 的调用结果返回。
随后突发奇想,用下面这种方式分别异步调用两次上面代码中的 AsyncTest 的函数:
    // 连续两次调用 AsyncTest 函数
    AsyncTest().then(() => {
      console.log("Async function executed");
    });
    AsyncTest().then(() => {
      console.log("Async function executed");
    });
   
结果发现虽然两次调用,但是只有一个调用有返回,个人的理解是:
  • 第一次调用 Promise ,给 onload 绑定回调函数,其中传入的 resolve 是第一个 Promise 的
  • 此时图片还没有加载完成
  • 第二次调用 Promise ,覆盖掉了 onload 的回调函数,其中的 resolve 变成了第二个 Promise 的
  • 图片加载完成,调用 onload 函数,其中调用的是第二个 Promise 的 resolve

    这样是否就意味着,第一次的 Promise 始终没有完成,保存在栈空间中,并在 EventLoop 中循环等待 resolve 的调用。 在图片加载完成后拍了堆快照,发现堆中确实留下了一个 Promise 的空间:

    请教一下,这是否意味着这块内存空间是否会始终被占用,以及利用 Promise 监听 onload 回调这种写法是否妥当?
  • xiaoming1992   
    用 addEventListener ,在 load 及 error 及 aborted 中 removeEventListener ,这样应该 OK
    ysc3839   
    感觉上会被 GC 掉,因为第一个 onload 被覆盖掉后就没有对象引用第一个 Promise 了。
    实际如何我说不清。
    Al0rid4l   
    https://www.zhihu.com/question/627670924/answer/3270699180
    另外不建议 Promise 监听事件, 因为事件可能返回多个值(多次触发), 而 Promise 只有一个值, 事件用 Observable(Rx)
    RedNax   
    理论上会被 GC 回收掉。
    第一个 Promise
    new Promise((resolve, reject) => {
    img.onload = () => {
    resolve("Image loaded successfully"); // 返回回调函数的结果
    };
    });
    不被 GC 是依赖 resolve 和 reject 的引用
    然而因为有第二个 Promise ,img.onload 不再 hold 这个函数:
    () => {
    resolve("Image loaded successfully"); // 返回回调函数的结果
    };
    那么函数里面的 resolve 也相当于没有被引用了。
    这样 GC 就知道这个 Promise 是可以安全 GC 的。
    RedNax   
    @Al0rid4l 大多数情况下一次性事件(比如 onload )也无所谓吧,用 RX 有点杀鸡用牛刀……
    ashong   
    第一次调用后 img 的 onload 已经完成,第二次的 promise 不会 resolve
    jchonc   
    我也猜楼上是对的,如果 AsyncTest 把 Message 加成参数再试试?
    Kaciras   
    没有引用的 Promise 会被 GC ,你可以搞个循环创建,然后在内存工具里看到锯齿状的图。
    jazzg62   
    promise 在 onload 中 resolve 是没有问题的,只是你写的这个代码有点问题,img 的 onload 函数只会触发一次,所以,也只会有一次 resolve 。
    你需要使用其他手段来判断 img 是否加载完成,如果没有加载完成,才绑定 onload 函数。
    一个不能 resolve 的 promise 确实会占用内存,会在事件循环一直等待处理
    ```javascript
    const message = () => {
    return new Promise((resolve, reject) => {
    if (img.complete) {
    resolve("Image loaded successfully"); // 返回回调函数的结果
    return ;
    }
    img.onload = () => {
    resolve("Image loaded successfully"); // 返回回调函数的结果
    };
    });
    };
    ```
    您需要登录后才可以回帖 登录 | 立即注册

    返回顶部