简体   繁体   中英

Promise is resolved but code stops in await

I followed Mozilla's docs . I created a function with a Promise inside. The Promise is resolved when the selector appears on the page (if not, the function runs again). Then the code should continue after await :

;(async () => {
  const titleSel = '.playbackSoundBadge__titleLink'
  document.querySelector(titleSel).click()
  const moreSel = 'button[title="More"]'
  await waitForEl(moreSel)
  console.log('after await')

  function waitForEl(selector) {
    return new Promise(resolve => {
      console.log(selector)
      if (document.querySelector(selector)) {
        console.log('resolved')
        resolve('resolved')
      } else {
        console.log('rejected')
        setTimeout(() => {
          waitForEl(selector)
        }, 100)
      }
    })
  }
})()

But strangely, 'resolved' is logged. But the code after await doesn't run. In other words, 'after await' is never logged.

Why is this, and how to fix it?

But strangely, 'resolved' is logged.
...
Why is this

waitForEl is called "recursively" (it schedules a call of itself via setTimeout ). Every call to waitForEl creates a promise, so you are creating multiple promises. The 'resolved' you see in the console is from one of those promises. You should also see one or more 'reject' messages.

The problem is that the "parent"/"top" promise is never resolved, because are not doing anything with the return value here:

waitForEl(selector)

The function returns a promise, but you are not doing anything with it, thus never resolving the promise that called this function.

An easy solution would be

waitForEl(selector).then(resolve)

But that also means you are creating promises recursively. It seems unnecessary to do this. Just define a simple function inside the promise that calls itself:

 function waitForEl(selector) {
    return new Promise(resolve => {
      console.log(selector)
      (function check()
        if (document.querySelector(selector)) {
          console.log('resolved')
          resolve('resolved')
        } else {
          console.log('rejected')
          setTimeout(check, 100);
        }
      }());
    })
  }

You should still add some condition that will reject the promise after some time, so it doesn't call setTimeout forever.

You have to pass waitForEl(selector) to resolve :

 ;(async () => { const moreSel = '.more' await waitForEl(moreSel) console.log('after await') function waitForEl(selector) { return new Promise(resolve => { console.log(selector) if (document.querySelector(selector)) { console.log('resolved') resolve('resolved') } else { console.log('rejected') setTimeout(() => { resolve(waitForEl(selector)) // here }, 1000) } }) } })() const btn = document.createElement("button"); btn.textContent = "add more"; const more = document.createElement("div"); more.textContent = "more"; more.classList.add("more"); btn.addEventListener("click", () => { document.body.appendChild(more); }); document.body.appendChild(btn);

In your code await waitForEl(moreSel) was never settled thus the log below couldn't be executed. If you pass a promise to resolve , the original promise will "bind" its fate to the passed one.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM