У меня есть две функции JS. Один зовет другого. В вызывающей функции я хотел бы вызвать другую, дождаться завершения этой функции и продолжить. Так, например / псевдокод:
function firstFunction(){
for(i=0;i<x;i++){
// do something
}
};
function secondFunction(){
firstFunction()
// now wait for firstFunction to finish...
// do something else
};
Я придумал это решение, но не знаю, разумно ли это сделать.
var isPaused = false;
function firstFunction(){
isPaused = true;
for(i=0;i<x;i++){
// do something
}
isPaused = false;
};
function secondFunction(){
firstFunction()
function waitForIt(){
if (isPaused) {
setTimeout(function(){waitForIt()},100);
} else {
// go do that thing
};
}
};
Это законно? Есть ли более элегантный способ справиться с этим? Возможно с jQuery?
firstFunction
именно делает это асинхронным? В любом случае - проверьте об обещанияхОтветы:
Один из способов справиться с такой асинхронной работой - использовать функцию обратного вызова, например:
Согласно предложению @Janaka Pushpakumara, теперь вы можете использовать функции стрелок для достижения того же самого. Например:
firstFunction(() => console.log('huzzah, I\'m done!'))
Обновление: я ответил на это довольно давно, и очень хочу его обновить. В то время как обратные вызовы абсолютно хороши, по моему опыту, они имеют тенденцию приводить к коду, который труднее читать и поддерживать. Есть ситуации, когда я все еще использую их, например, для передачи событий прогресса и т.п. в качестве параметров. Это обновление только для того, чтобы подчеркнуть альтернативы.
Также в первоначальном вопросе не упоминается асинхронность, поэтому, если кто-то запутается, если ваша функция синхронная, она будет заблокирована при вызове. Например:
Если, хотя подразумевается, что функция является асинхронной, то, как я обычно имею дело со всей моей асинхронной работой сегодня, - с помощью async / await. Например:
IMO, async / await делает ваш код более читабельным, чем прямое использование обещаний (большую часть времени). Если вам нужно обработать ошибки перехвата, используйте его с try / catch. Подробнее об этом читайте здесь: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function .
источник
Используйте async / await:
затем используйте await в другой функции, чтобы дождаться ее возвращения:
источник
$(function() { await firstFunction(); secondFunction(); });
,?await
можно использовать только внутриasync
метода. Так что если вы сделаете свою родительскую функциюasync
можно вызвать как многиеasync methods
изнутри или без ,await
что вы хотите.await
этоsetTimeout
?Похоже, вы упустили важный момент: JavaScript - это однопоточная среда выполнения. Давайте еще раз посмотрим на ваш код, обратите внимание, что я добавил
alert("Here")
:Вам не нужно ждать
isPaused
. Когда вы увидите предупреждение «Здесь»,isPaused
будетfalse
уже иfirstFunction
вернется. Это потому, что вы не можете «уступить» изfor
цикла (// do something
), цикл может не прерываться и сначала его нужно будет полностью завершить (более подробно: обработка потоков Javascript и условия гонки ).Тем не менее, вы все еще можете сделать поток кода внутри
firstFunction
асинхронным и использовать либо обратный вызов, либо обещание уведомить вызывающую сторону. Вам придется отказаться отfor
цикла и смоделировать его с помощьюif
( JSFiddle ):Кстати, в JavaScript 1.7 введено
yield
ключевое слово в составе генераторов . Это позволит «пробивать» асинхронные дыры в синхронном потоке кода JavaScript ( более подробно и пример ). Тем не менее, поддержка браузеров для генераторов в настоящее время ограничена Firefox и Chrome, AFAIK.источник
Элегантный способ дождаться завершения одной функции - использовать Promises с функцией async / await .
setTimeout
для того, чтобы продемонстрировать ситуацию, когда выполнение инструкций займет некоторое время.await
выполнить первую функцию, прежде чем продолжить выполнение инструкций.Пример:
Примечание:
Вы могли бы просто без какого - либо значения , как так . В моем примере, я со значением , что я могу затем использовать во второй функции.
resolve
Promise
resolve()
resolved
Promise
y
источник
Единственная проблема с обещаниями заключается в том, что IE их не поддерживает. Edge делает, но есть много IE 10 и 11 там: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise (совместимость внизу)
Итак, JavaScript однопоточный. Если вы не делаете асинхронный вызов, он будет вести себя предсказуемо. Основной поток JavaScript выполнит одну функцию полностью перед выполнением следующей, в порядке их появления в коде. Гарантировать порядок для синхронных функций тривиально - каждая функция будет выполняться полностью в том порядке, в котором она была вызвана.
Думайте о синхронной функции как об элементарной единице работы . Основной поток JavaScript выполнит его полностью в порядке появления операторов в коде.
Но добавьте асинхронный вызов, как в следующей ситуации:
Это не делает то, что вы хотите . Он мгновенно выполняет функцию 1, функцию 2 и функцию 3. Загрузка div мигает, и он исчезает, в то время как вызов ajax почти не завершен, хотя
makeAjaxCall()
и вернулся. Осложнение состоит в том, чтоmakeAjaxCall()
его работа разбита на куски, которые постепенно продвигаются при каждом вращении основного потока JavaScript - он ведет себя асинхронно. Но тот же основной поток за один оборот / прогон выполнил синхронные части быстро и предсказуемо.Итак, способ, которым я справился : Как я уже сказал, функция - это атомная единица работы. Я объединил код функции 1 и 2 - я поместил код функции 1 в функцию 2 перед асинхронным вызовом. Я избавился от функции 1. Все до асинхронного вызова, включая асинхронный вызов, выполняется предсказуемо, по порядку.
ТОГДА, когда асинхронный вызов завершается после нескольких вращений основного потока JavaScript, он вызывает функцию 3. Это гарантирует порядок . Например, в ajax обработчик события onreadystatechange вызывается несколько раз. Когда он сообщит о завершении, вызовите последнюю функцию, которую вы хотите.
Я согласен, что это грязнее. Мне нравится, когда код должен быть симметричным, мне нравится, когда функции выполняют одно (или близко к нему), и мне не нравится, когда вызов ajax каким-либо образом отвечает за отображение (создание зависимости от вызывающего). НО, с асинхронным вызовом, встроенным в синхронную функцию, должны быть достигнуты компромиссы, чтобы гарантировать порядок выполнения. И я должен написать для IE 10, так что никаких обещаний.
Резюме : для синхронных звонков гарантированный порядок тривиален. Каждая функция выполняется полностью в том порядке, в котором она была вызвана. Для функции с асинхронным вызовом единственный способ гарантировать порядок - следить за завершением асинхронного вызова и вызывать третью функцию при обнаружении этого состояния.
Для обсуждения потоков JavaScript см. Https://medium.com/@francesco_rizzi/javascript-main-thread-dissected-43c85fce7e23 и https://developer.mozilla.org/en-US/docs/Web/JavaScript/. EventLoop
Кроме того, еще один похожий, высоко оцененный вопрос на эту тему: как я должен вызывать 3 функции, чтобы выполнять их одну за другой?
источник
Это то, что я придумал, так как мне нужно выполнить несколько операций в цепочке.
источник
Ваше основное веселье будет называться firstFun, а затем закончится ваше следующее веселье.
источник