【问题标题】:Execute javascript function after previous one finishes前一个完成后执行javascript函数
【发布时间】:2019-02-13 13:42:45
【问题描述】:

我有一个具有 setTimeout 的函数“showElement”。如何使对“btnSend”的 eventListener 中的函数的调用在另一个之后立即执行?

我尝试使用 .then() 但没有成功。

document.getElementById('btnSend').addEventListener('click', e => {
    e.preventDefault();
    result = validateInputs(email, subject, message);
    if(result) {
        showElement(document.getElementById('formGroupSpinner'), 2000);
        showElement(document.getElementById('formGroupSuccessImg'), 2000);
        resetForm();
    }
});

//expects an html element and a number representing miliseconds. Shows the html element for that amount of time.
function showElement(element, mSeconds) {
    element.classList.remove('d-none');
    element.classList.add('d-block');
    setTimeout( () => {
        element.classList.remove('d-block');
        element.classList.add('d-none');
    }, mSeconds);
}

两个函数同时执行。

【问题讨论】:

  • 您好 Floro,您似乎是 JS 新手,寻找 JavaScript 回调。
  • 请也添加您的 HTML :)
  • @jo_va 不相关
  • 要使用then,您需要create and return a promise

标签: javascript asynchronous settimeout


【解决方案1】:

有很多不同的方法,但我建议使用这样的 Promise:

document.getElementById('btnSend').addEventListener('click', e => {
    e.preventDefault();
    var result = validateInputs(email, subject, message);
    if(result){
        showElement(document.getElementById('formGroupSpinner'), 2000).then(()=>{
            return showElement(document.getElementById('formGroupSuccessImg'), 2000);
        }).then(()=>{
            resetForm();
        });
    }
});

//expects an html element and a number representing miliseconds. Shows the html element for that amount of time.
function showElement(element, mSeconds) {
    return new Promise((resolve, reject) => {
        element.classList.remove('d-none');
        element.classList.add('d-block');
        setTimeout( () => {
            element.classList.remove('d-block');
            element.classList.add('d-none');
            resolve();
        }, mSeconds);
    });
}

基本上,.then() 之后的函数只有在您调用 resolve(); 时才会执行。

您也可以使用callbackasync / await

【讨论】:

  • 不过你会想unnest your then calls
  • @Bergi 对不起,我不明白你的意思。如果这很重要,您可以编辑答案吗?
  • 不像“不起作用”那么重要,但它仍然是更好的风格。已编辑。
  • 谢谢,在尝试了不同的方法后,这个对我有用。
【解决方案2】:

您可以在函数结束后使用回调来执行其他指令:

//First you add a param "callback" to the function
function showElement(element, mSeconds, callback) {
    element.classList.remove('d-none');
    element.classList.add('d-block');
    setTimeout( () => {
        element.classList.remove('d-block');
        element.classList.add('d-none');
        //Then you ask if the callback function is present and call it
        if(callback && typeof callback === "function") callback();
    }, mSeconds);
}

//Then use it in your event like this:
document.getElementById('btnSend').addEventListener('click', e => {
    e.preventDefault();
    result = validateInputs(email, subject, message);
    if(result) {
        showElement(document.getElementById('formGroupSpinner'), 2000, () => {
            showElement(document.getElementById('formGroupSuccessImg'), 2000);
            resetForm();
        });  
    }
}); 

【讨论】:

    【解决方案3】:

    您可以使用Promise 来执行此操作。您必须将您的 showElement() 函数包装到一个承诺中,并在 setTimeout 触发时调用承诺解析器。 然后你的调用代码可以pipe你的promise和then一起:

    showElement(document.getElementById('formGroupSpinner'), 2000).then(() => {
        showElement(document.getElementById('formGroupSuccessImg'), 2000).then(() => {
            resetForm();
        });
    });
    

    但是,这很快就会导致回调地狱。

    您可以使用async/await 来避免这种情况。 您将您的函数标记为async,然后您可以在其中使用await 等待promise 解决,然后再继续下一个:

    await showElement(document.getElementById('formGroupSpinner'), 2000);
    await showElement(document.getElementById('formGroupSuccessImg'), 2000);
    resetForm();
    

    这是一个工作演示:

    document.getElementById('btnSend').addEventListener('click', async e => {
        e.preventDefault();
        await showElement(document.getElementById('formGroupSpinner'), 2000);
        await showElement(document.getElementById('formGroupSuccessImg'), 2000);
    });
    
    function showElement(element, mSeconds) {
      return new Promise((resolve, reject) => {
        element.classList.remove('d-none');
        element.classList.add('d-block');
        setTimeout(() => {
            element.classList.remove('d-block');
            element.classList.add('d-none');
            resolve();
        }, mSeconds);
      });
    }
    .d-none {
      display: none;
    }
    
    .d-block {
      display: block;
    }
    <button id="btnSend">Send</button>
    
    <div id="formGroupSpinner" class="d-none">Spinner</div>
    <div id="formGroupSuccessImg" class="d-none">Success image</div>

    【讨论】:

    • 谢谢,在尝试了不同的方法后,这个对我有用。但是我最终使用了 Bergi 提供的解决方案
    【解决方案4】:

    最简单的方法就是将第二个 showElement 更改为 4000 而不是 2000

    这样一个超时时间为 2 秒,另外一个为 4 秒。

    【讨论】:

    • 是的,这可行,但也很不雅
    • @Sv443 并非一切都必须过于复杂,所以它是“优雅的”
    • 嗯,不仅如此,而且更不可靠。
    【解决方案5】:

    要创建一个 Promise 链,您首先必须有一个 Promise。

    function showElement(element, mSeconds) {
      return new Promise(function(resolve,reject){
        element.classList.remove('d-none');
        element.classList.add('d-block');
        setTimeout( () => {
          element.classList.remove('d-block');
          element.classList.add('d-none');
          resolve();
        }, mSeconds);
      }
    }
    

    那么你可以使用showElement().then(/*something here */)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多