Выполнение функции после завершения другой (асинхронной) функции в JavaScript - PullRequest
3 голосов
/ 16 июня 2019

Пожалуйста, дайте мне ванильное решение JS, так как я новичок в кодировании, и введение библиотек могло бы меня еще больше запутать.

У меня есть две функции в программе: changeText содержит асинхронные функции setTimeoutкоторые исчезают и вводятся в текст за X секунд и userNameinput, который позволяет пользователю вводить текстовый ввод, а затем отображать его обратно в браузере.

Проблема, с которой я сталкиваюсь, заключается в том, что usernameinput выполняется вдольс функцией changeText. Моя цель состоит в том, чтобы сначала выполнить функцию changeText и завершить ее, а затем выполнить userNameInput (строка ввода текста) сразу после.

Как вы можете видеть в моем коде, я реализовалОбратный звонок в попытке решить эту проблему.Я создаю новую функцию с именем welcome, чтобы связать вместе функции changeText и useNameInput таким образом, чтобы при вызове welcome сначала выполнялся changeText, а затем завершался пользовательский вызов userNameInput, упакованный в обратный вызов.Почему-то я считаю, что поскольку функции setTimeout в функциях changeText помещаются в очередь за пределами среды Javascript на некоторое время X, JS видит, что в стеке ничего нет, и продолжает выполнять usernameInput без ожидания.Пожалуйста помоги!Застрял слишком долго!Заранее спасибо.

HTML:

<div id="h1">Hello,<br></div>
    <div id="inputDiv"></div>

CSS:

 #h1{
      opacity: 0;
      transition: 1s;
}

JS:

function fadeIn() {
  document.getElementById('h1').style.opacity = '1';
}

function fadeOut() {
  document.getElementById('h1').style.opacity = '0';
}

var dialogue = ['Hello,', 'My name is Jane.', 'I have a dog!', 'What is your name?'];

var input = document.createElement("input");
input.setAttribute("type", "text");
input.setAttribute("value", "");
input.setAttribute("placeholder", "Type your name then press Enter");
input.setAttribute("maxLength", "4");
input.setAttribute("size", "50");
var parent = document.getElementById("inputDiv");
parent.appendChild(input);
parent.style.borderStyle = 'solid';
parent.style.borderWidth = '0px 0px .5px 0px';
parent.style.margin = 'auto';


function changeText() {
  var timer = 0;
  var fadeOutTimer = 1000;
  for (let i = 0; i < dialogue.length; i++) {
    setTimeout(fadeIn, timer);
    setTimeout(fadeOut, fadeOutTimer);
    setTimeout(function () {
      document.getElementById('h1').innerHTML = dialogue[i];
    }, timer);
    timer = (timer + 3000) * 1;
    fadeOutTimer = (fadeOutTimer + 3000) * 1.1;
    console.log(timer, fadeOutTimer);
  }
}

function welcome(callback) {
  changeText();
  callback();
}
welcome(function () {
  function userNameInput() {
    function pressEnter() {
      var userName = input.value;
      if (event.keyCode == 13) {
        document.getElementById('h1').innerHTML = "Nice to meet you" +
          " " + userName + "!";
      }
    }
    input.addEventListener("keyup", pressEnter);
  }
  userNameInput();
});

1 Ответ

1 голос
/ 16 июня 2019

Если бы я хотел подвести итог, проблема, с которой вы работаете, следующая:

У вас есть две функции, которые используют setTimeout для выполнения некоторого кода с задержкой. Поскольку setTimeout не блокируется, он «мгновенно» зарегистрирует обратный вызов setTimeout и продолжит выполнение оставшейся функции.

function a() {
    setTimeout(function() {
        console.log('a');
    }, 500)
} 

function b() {
    setTimeout(function() {
        console.log('b');
    }, 250)
}

a();
b();

Здесь вы хотели бы иметь «a» через 500 мс, затем «b» через 250 мс, но вы получите «b» через 250 мс и «a» через 250 мс.

Старый способ сделать это - использовать обратный вызов, подобный этому:

function a(callback) {
    setTimeout(function() {
        console.log('a');
        callback();
    }, 500)
} 

function b() {
    setTimeout(function() {
        console.log('b');
    }, 250)
}

a(b)

Таким образом, a сама вызовет b.

Современный способ сделать это - использовать обещания / async / await:

function a() {
    return new Promise(function(resolve) {
        setTimeout(function() {
            console.log('a');
            resolve();
        }, 500)
    });
}

function b() {
    return new Promise(function(resolve) {
        setTimeout(function() {
            console.log('b');
            resolve();
        }, 250);
    });
}

, а затем позвоните:

a().then(b).then(function() {/* do something else */})

или, внутри асинхронной функции:

async function main() {
    await a();
    await b();
    // do something else
}

main()
...