2014-08-27 2 views
0

Я хочу вызвать несколько функций один за другим рекурсивно с помощью setTimeout.Вызов функции рекурсивно с помощью setTimeout

var flag = 0 ; 
function slave1(){ 
    if(flag < 60) { 
     var COPY_PO_LINE_DIV = document.getElementById("DOM_ELEMENT1"); // Checking if DOM has loaded or not. If yes then doing something. 
     if (COPY_PO_LINE_DIV != null) { 
      flag = 0; 
      //doing something 
     } else { 
      setTimeout(slave1,2000); //waiting for 2 seconds and checking again. 
     } 
    } 
} 

//doing similar task 
function slave2(){ 
    if(flag < 60) { 
     var COPY_PO_LINE_DIV = document.getElementById("DOM_ELEMENT2");    
     if (COPY_PO_LINE_DIV != null) { 
      flag = 0; 
      //doing something 
     } else { 
      setTimeout(slave2,2000); 
     } 
    } 
} 

function master() { 
    slave1(); 
    console.log("Without completing slave1 function."); 
    slave2(); 
} 

Через master() функции я хочу вызвать множественные функции один за другим, однако в нынешней ситуации его вызывающему slave2() без завершения slave1(). Как я могу убедиться, что выполнено slave1(). Если элемент DOM не загружен, он должен выполняться 60 раз каждые 2 секунды, а затем он должен выходить из slave1() и перейти к следующему.

Я хочу выполнить ту же функцию в течение 60 раз, если элемент dom не загружен без возврата элемента управления к следующей функции.

+0

ли вы использовать любую библиотеку JS или же он должен быть чистым JS? – Tomalak

+0

Pure JS .................... –

ответ

3

Вам необходимо настроить slave1 для запуска обратного вызова, когда он будет завершен, который будет slave2.

function slave1(callback){ 
    if(flag < 60) { 
     var COPY_PO_LINE_DIV = document.getElementById("DOM_ELEMENT1"); // Checking if DOM has loaded or not. If yes then doing something. 
     if (COPY_PO_LINE_DIV != null) { 
      flag = 0; 
      //doing something 
      callback(); 
     } else { 
      setTimeout(slave1,2000); //waiting for 2 seconds and checking again. 
     } 
    } 
} 

function slave2(){...} 

function master() { 
    slave1(slave2); 
    console.log("Without completing slave1 function."); 
} 

Это ваша основная цепочка javascript. Если у вас есть больше рабов вы можете захотеть взглянуть на async.series иначе вы идете в обратного вызова ад, как Gabs00 поставил это красиво:

slave1(function(){ 
    slave2(function(){ 
     slave3(function(){ 
      slave4(slave5); 
     }); 
    }); 
}); 

Если вам нужно передать значения в функции обратного вызова, то вам необходимо использовать промежуточный анонимный которая, в свою очередь, вызывает предполагаемый обратный вызов с соответствующими аргументами. Чтобы сделать это, вам нужно определить свои функции, с тем, что они используют аргументы: (?, Если когда-либо)

function slave1(str, callback){...} 
function slave3(i, callback){...} 

slave1("some argument", function(){ 
    slave2("another argument", function(){ 
     slave3(1, function(){ 
      slave4(2, slave5); 
     }); 
    }); 
}); 
+0

Спасибо! Helpfull ... но предположим, что у меня есть 5 функций подряд, чем то, как я могу сделать цепочку из них. –

+1

@Mike Затем вы эффективно вводите обратный вызов ада, считаете обещания – Gabs00

+0

@ Artjom- Если мне нужно передать несколько аргументов? –

0

Вашей slave2 функция должна быть передана slave1 функции в качестве обратного вызова и должна быть вызвана в slave1 после его завершения. Ваша текущая ситуация довольно распространена, поскольку функция setTimeout() является асинхронной, поэтому интерпретатор JS не дожидается завершения функции, но устанавливает результат setTimeout() в конце Evet Loop и продолжает обработку метода master().

1

Рассмотрите возможность использования таких обещаний. Здесь реализация на вершине jQuery, другие библиотеки обещаний работают аналогично.

function waitForElement(elementId, maxTries, checkInterval) { 
    var d = $.Deferred(), intvalID, checkFunc; 

    // set up default values 
    maxTries = maxTries || 60; 
    checkInterval = checkInterval || 2000; 

    checkFunc = function() { 
     var elem = document.getElementById(elementId); 
     if (maxTries-- > 0 && elem) { 
      clearInterval(intvalID); 
      d.resolve(elem); 
     } 
     if (maxTries <= 0) { 
      clearInterval(intvalID); 
      d.reject(elementId); 
     } 
    }; 

    // set up periodic check & do first check right-away 
    intvalID = setInterval(checkFunc, checkInterval); 
    checkFunc(); 

    return d.promise(); 
} 

Теперь, если вы хотите проверить элементы один за другим, вы можете каскадно звонки, как это:

function master() { 
    waitForElement("DOM_ELEMENT1").done(function (elem1) { 
     waitForElement("DOM_ELEMENT2").done(function (elem2) { 
      alert("elem1 and elem2 exist!"); 
      // now do something with elem1 and elem2 
     }).fail(function() { 
      alert("elem1 exists, but elem2 was not found."); 
     }); 
    }).fail(function() { 
     alert("elem1 not found."); 
    }); 
} 

или вы можете сделать это параллельно и имеют функцию обратного вызова вызывается, когда все существуют элементы:

function master() { 
    $.when(
     waitForElement("DOM_ELEMENT1"), 
     waitForElement("DOM_ELEMENT2") 
    ) 
    .done(function (elem1, elem2) { 
     alert("elem1 and elem2 exist!"); 
     // now do something with elem1 and elem2 
    }) 
    .fail(function() { 
     alert("not all elements were found before the timeout"); 
    }); 
} 
0

Для передачи аргументов в функции создание анонимных функций оказывается излишним. Вместо этого попробуйте использовать «bind». Так что, если у вас есть

function slave1(str, callback){...} 
function slave2(str, callback){...} 
function slave3(i, callback){...} 
function slave4(i, callback){...} 
function slave5() 

Вместо использования

slave1("some argument", function(){ 
    slave2("another argument", function(){ 
     slave3(1, function(){ 
      slave4(2, slave5); 
     }); 
    }); 
}); 

Рассмотрите возможность использования

slave1("some argument", 
    slave2.bind(null, "another argument", 
     slave3.bind(null, 1, 
      slave4.bind(null, 2, slave5) 
     ) 
    ) 
); 

Намного проще, более эффективным с точки зрения памяти и загрузки процессора. Теперь, как сделать это с SetTimeout:

slave1("some argument", 
    setTimeout.bind(null, slave2.bind(null, "another argument", 
     setTimeout.bind(null, slave3.bind(null, 1, 
      setTimeout.bind(null, slave4.bind(null, 2, 
       setTimeout.bind(null, slave5, 0) 
      ),0) 
     ),0) 
    ),0) 
); 

Я объяснил проблему более подробно на http://morethanslightly.com/index.php/2014/09/executables-the-standard-solution-aka-mind-the-bind/

Смежные вопросы