承诺解决一次

Promise resolving once

我的代码中的 Promise 仅在第一次执行时解析,它是简单的表单提交和 reCAPTCHA 验证。通过调试,我知道浏览器解释器到达 await captchaVerification() 行并停在那里。第一次执行没有任何错误。

contactForm.addEventListener('submit', async (e) => {
    e.preventDefault();
    await captchaVerification()
    const data = new FormData(contactForm)
    _alert.innerHTML = 'Sending message...'
    _alert.setAttribute('class', `alert show`);
    ajax(contactForm.method, contactForm.action, data)
        .then(([r, t]) => outcome(r ? r = 'success' : r = 'error', t))
        .catch(e => outcome('error', e))
});

hastebin 的完整上下文:https://hastebin.com/oyuvoyeluv.js

从你发布的 link 我可以看到在你的 captchaVerification 函数中,你检查之前是否呈现过验证码,如果没有你呈现并且 resolvereject 承诺。问题是如果 isRendered 为真,你永远不会 resolvereject

function captchaVerification() {
    return new Promise((resolve, reject) => {
        captcha.style.display = 'block';

        const verifyCallback = (response) => {
            if (response) {
                captcha.style.display = 'none'
                grecaptcha.reset()
                return resolve(response)
            } else {
                grecaptcha.reset()
                return reject('Invalid captcha verification.')
            }
        }

        // The problem is here as you do nothing if the captcha was 
        // previously rendered.
        if (!isRendered) {
            grecaptcha.render('g-recaptcha', {
                'sitekey': 'my-secret-key',
                'theme': 'dark',
                'callback': verifyCallback
            })
            isRendered = true;
        }
    })
}

这完全取决于 captchaVerification 实施。 if function return 同样的承诺。下次解决不了。就像 Singelton。所以最好总是创建 new promise

const promise = new Promise(r => setTimeout(r, 100, Math.random()))
const captchaVerification = () => promise;

const captchaVerificationRe = () => new Promise(r => setTimeout(r, 100, Math.random()));

async function main() {
  let res = await captchaVerification();
  console.log(res); // 0.3251446189302283
  res = await captchaVerification("sffsfs");
  console.log(res); // 0.3251446189302283

  res = await captchaVerificationRe();
  console.log(res); // 0.06299211055753262
  res = await captchaVerification("sffsfs");
  console.log(res); // 0.721527810718094
}
main();

根据您发布的代码,您有以下选择:

第一个选项使用 then

contactForm.addEventListener('submit', (e) => {
    e.preventDefault();
    captchaVerification().then((response) => {
        // check if response is ok
        if(response ... is not what expected end here) {
            return false;
        }
        const data = new FormData(contactForm)
       _alert.innerHTML = 'Sending message...'
       _alert.setAttribute('class', `alert show`);
       ajax(contactForm.method, contactForm.action, data)
        .then(([r, t]) => outcome(r ? r = 'success' : r = 'error', t))
        .catch(e => outcome('error', e))
    });

});

第二个选项使用await

contactForm.addEventListener('submit', async (e) => {
    e.preventDefault();
    let response = await captchaVerification();
        // check if response is ok
        if(response ... is not what expected end here) {
            return false;
        }
        const data = new FormData(contactForm)
       _alert.innerHTML = 'Sending message...'
       _alert.setAttribute('class', `alert show`);
       ajax(contactForm.method, contactForm.action, data)
        .then(([r, t]) => outcome(r ? r = 'success' : r = 'error', t))
        .catch(e => outcome('error', e))      
});

您也可以尝试更改 hastebin 示例中的两到三行。

var isRendered = false;
async function captchaVerification() {
    return await new Promise((resolve, reject) => {
        captcha.style.display = 'block'
        const verifyCallback = (response) => {
            if (response) {
                captcha.style.display = 'none'
                grecaptcha.reset()
                return resolve(response)
            } else {
                grecaptcha.reset()
                return reject('Invalid captcha verification.')
            }
        }
        if (!isRendered) {
            grecaptcha.render('g-recaptcha', {
                'sitekey': 'my-secret-key',
                'theme': 'dark',
                'callback': verifyCallback
            })
            isRendered = true;
        }
    })
}

对于所有想知道的人来说,这是解决我的问题的一段代码。 基本上 Google API 不允许用户在 相同的 HTML 元素 上渲染 相同的验证码对象 一次。我通过为我的验证码动态创建 HTML 元素 并将其删除来解决它 after 我收到来自 Google 的响应API 服务器端验证(success/error)。

https://gist.github.com/ANTOSzbk/75ed7003e914162550f61399122a3bd4