2015-05-28 4 views
0

Я новичок (2 дня!) В мире JavaScript, и мой единственный опыт предшествующего кодирования в Java, где выполнение операторов происходит последовательно. Я понимаю, что, по крайней мере, я читал, что JavaScript является асинхронным, что означает, что если есть инструкция, которая занимает много времени для выполнения, следующий оператор выполняется, не поддерживая программу для первого оператора. Я столкнулся с обратными вызовами (на самом деле!), Но я не мог понять, как их можно использовать для определения порядка выполнения. Я написал фрагмент кода, чтобы понять, как это можно сделать, и я уверен, что смогу воспользоваться некоторой помощью.Как установить определенный порядок выполнения при использовании асинхронных вызовов?

console.log("Beginning"); 

function Test(callback){ 
    setTimeout(function(callback){ 
     console.log("Something that takes a lot of time"); 
    },5000); 
    callback(); 
} 

function tstCallBack(){ 
    console.log("Should come last"); 
} 

Test(tstCallBack); 

То, что я хочу для вывода на дисплей -

Beginning 
Something that takes a lot of time 
Should come last 

Но выход я получаю -

Beginning 
Should come last 
Something that takes a lot of time 

Что я могу сделать, чтобы получить выход в как я этого хочу?

+0

«JavaScript является асинхронным, что означает, что если есть заявление, которое занимает много времени, чтобы xecute, следующий оператор выполняется, не поддерживая программу для первого оператора. " Это неверно, javascript имеет асинхронные операторы true, но это происходит не потому, что функция занимает много времени, когда поток автоматически перескакивает дальше, что зависит от того, является ли это функцией async или нет. Btw Java может быть асинхронной в более поздних версиях, она намного реже. –

+0

@NexusDuck - Большое вам спасибо! Это было то, чего мне не хватало. То есть (исправьте меня, если я ошибаюсь), JavaScript имеет эти встроенные функции, которые подвержены/или вызывают задержки, и они сделаны асинхронными, чтобы избежать проблем; что означает, что мы не можем настраивать собственные асинхронные функции (не полагаясь на что-то встроенное) Я прав? – Savvy

+0

Вы правы, посмотрите на ответ @ jfriend00, у него более подробная версия (важно, что javascript имеет более асинхронный характер, потому что он однопоточный, а не Java, который может быть многопоточным) –

ответ

2

Давайте проясним некоторые вещи, в то, что вы сказали:

Я новый (2 дня !!) в мире JavaScript и моим единственным предварительного кодирования опыт в Java, где выполнение операторов происходит последовательно. Я понимаю, что, или, по крайней мере, я читал, что JavaScript является асинхронным, что означает, что если есть инструкция, которая принимает длительное время для выполнения, то следующий оператор выполняется без сохранения программы для первого оператора.

Это не то, как это работает. Данная функция является либо асинхронной, либо ее синхронной по дизайну.Он не имеет абсолютно никакого отношения к тому, сколько времени требуется для выполнения. У вас может быть очень быстрая функция async или очень длинная синхронная функция. Что определяет, является ли функция асинхронной или нет, как она разработана. Если он использует асинхронные входы/выходы или таймеры или любую другую асинхронную инфраструктуру, то по меньшей мере часть выполнения функции является асинхронной. Это означает, что некоторые из функций закончат LATER, а некоторые из кода сразу после этого вызова функции будут выполняться до того, как закончится асинхронная часть.

я наткнулся на обратные вызовы (на самом деле очень много !!), но я не мог видеть, как они могут быть использованы для определения порядка выполнения. Я написал фрагмент кода , чтобы понять, как это можно сделать, и я уверен, что смогу использовать некоторую помощь .

Обратные вызовы используются для уведомления вызывающего кода при завершении какой-либо асинхронной операции. Это можно использовать для использования результата асинхронной операции или может использоваться для выполнения следующей части кода, которая должна запускаться последовательно после завершения операции async.

В вашем примере кода, если вы хотите получить нужную последовательность, вы должны вызвать обратный вызов внутри обратного вызова setTimeout(), чтобы он вызывался после того, как setTimeout() вызвал выполнение, что дает вам желаемую последовательность.

Вы также должны удалить аргумент callback для обратного вызова setTimeout. Этот обратный вызов не передается с этим аргументом, поэтому объявление его там просто неверно. Его можно получить непосредственно из родительской функции через замыкание, как показано здесь:

console.log("Beginning"); 

function Test(callback){ 
    setTimeout(function(){ 
     console.log("Something that is asynchronous"); 
     // call the callback here to indicate to the calling code 
     // that the asynchronous operation is now complete 
     callback(); 
    },5000); 
    console.log("After Setting Timer"); 
} 

function tstCallBack(){ 
    console.log("Should come last"); 
} 

Test(tstCallBack); 

Это будет генерировать последовательность в консоли:

Начиная

После установки таймера

Что-то, что является асинхронным

Должно наступить последнее


Концептуально, двигатель Javascript работает один поток, и что один поток использует очередь событий. Итак, в вашей функции выше, это то, что происходит.

  1. Выполнено первое console.log("Beginning");.
  2. Test(tstCallback) называется.
  3. В рамках выполнения функции Test() запланирован таймер. Это регистрирует таймер, встроенный в JS-движок.
  4. Выполнение кода в Test() продолжается, console.log("After Setting Timer"); выполняется, а затем эта функция заканчивается.
  5. Текущий поток выполнения JS завершается, и если в очереди событий нет ничего другого, то JS-движок не имеет ничего общего, но ждать следующего события.
  6. Спустя некоторое время (5 секунд, когда установлен таймер) внутренний таймер срабатывает, и он помещает событие таймера в очередь событий JS.
  7. Поскольку в настоящий момент другого действия JS нет, событие таймера вытаскивается из очереди событий и выполняется. Это означает, что вызывается исходный обратный вызов, который был зарегистрирован для таймера.
  8. Когда вызывается обратный вызов таймера, он выполняет линию console.log("Something that is asynchronous");, а затем вызывает callback().
  9. Затем вызывается функция tstCallback и выполняется console.log("Should come last");.
  10. Событие async завершает выполнение, а механизм JS смотрит, есть ли в очереди событий больше событий. Если это так, следующее событие вытягивается из очереди и запускается.

Есть ряд очень хороших ссылок о том, как Javascript обрабатывает асинхронные операции:

How does JavaScript handle AJAX responses in the background?

How Javascript Timers Work

Do I need to be concerned with race conditions with asynchronous Javascript?

+0

Не нужно ставить обратный вызов как параметр функции setTimeout, хотя он доступен внутри функции из-за закрытий –

+0

@NexusDuck - вы правы , Я исправил его. – jfriend00

+0

@ jfriend00 - Я, наконец, понимаю ... Спасибо, много ооочень. Ты спас меня от многих страданий. Хотел бы, чтобы у меня была репутация, чтобы поддержать ... – Savvy

0

Место будет выполняться обратный вызов внутри setTimeout, а не снаружи, как callback первого до SetTimeout делает, Javascript не будет ждать setTimeout исполнения (as JS is synchronous by nature) и выполняет следующую строку и, следовательно, вы не получите желаемый выпуск.

console.log("Beginning"); 
function Test(callback){ 
    setTimeout(function(){ 
    console.log("Something that takes a lot of time"); 
    callback(); 
    },5000); 
} 
function tstCallBack(){ 
    console.log("Should come last"); 
} 
Test(tstCallBack); 

Demo

1

Много того, что вы сказали, это не так. JavaScript является последовательным так же, как Java, но асинхронные вызовы выполняются чаще. Если вы хотите, чтобы ваш callback вызывался после долгой вещи, вы должны вызывать его после долгой программы. Вроде так -

console.log("Beginning"); 
function Test(callback){ 
    setTimeout(function(callback){ 
    console.log("Something that takes a lot of time"); 
    callback(); 
    },5000); 

} 
function tstCallBack(){ 
    console.log("Should come last"); 
} 
Test(tstCallBack); 
+1

второй вызов обратного вызова, должен быть удален внутри функции тестирования. – wonderbell

+0

@aSharma Действительно - я даже не заметил, что это честно. –

+0

Большое спасибо, но я знал об этом конкретном способе этого. Я просто подумал, что, возможно, был другой путь. Я до сих пор не понимаю значения обратных вызовов :( – Savvy

0

Я изменил ваш код, как показано ниже, чтобы получить желаемый результат.

console.log("Beginning"); 
function Test(callback){ 

    console.log("Something that takes a lot of time"); 
    setTimeout(callback,5000); 
} 

function tstCallBack(){ 
    console.log("Should come last"); 
} 
Test(tstCallBack); 

SetTimeout принимает функцию обратного вызова, которая будет выполнена по истечению заданного интервала времени

Применение SetTimeout является асинхронной частью. Когда выполняется вышеуказанный код, сначала печатается инструкция консоли «Начало», а затем функция Test называется передачей функции, которая должна выполняться асинхронно после 500 мс.

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