Синхронный и асинхронный JavaScript (механизм выполнения)

JavaScript

Прежде всего, я поставил его в начале статьи, акцентируя внимание на двух моментах:

  1. JavaScript — это однопоточный язык.
  2. Цикл событий — это механизм выполнения JavaScript.

Хорошо, тогда приступим к основному содержанию этой статьи.Так как js однопоточный, значит он выполняется сверху вниз при выполнении кода.Возьмем кусок кода:

setTimeout(function(){
    console.log('定时器开始')
});
new Promise(function(resolve){
    console.log('Promise开始');
    resolve();
}).then(function(){
    console.log('执行then函数')
});
console.log('代码执行结束');

Увидев приведенный выше код, вы можете дать ответ: «Таймер запускается», «Промис начинается», «Выполняется, затем функция», «Выполнение кода заканчивается». Затем давайте проверим, что вывод:

  • Обещание начинается
  • выполнение кода заканчивается
  • выполнить функцию then
  • таймер запускается

Одиночный поток JavaScript

Увидев такой ответ, давайте изучим механизм его выполнения. Что касается предварительного парсинга, я опубликую отдельную статью позже. Здесь мы в основном рассмотрим механизм выполнения, лежащий в основе. Мы говорим, что JavaScript — это однопоточный язык. откуда взялась его "многопоточность"? Все это смоделировано. Давайте через некоторое время взглянем на этого "многопоточного бумажного тигра".

Синхронный и асинхронный JavaScript (первый взгляд на цикл событий)

Поскольку это один поток, мы можем думать, например, о том, чтобы пойти в банк, чтобы справиться с делами, и когда мы доберемся туда, нам придется встать в очередь, чтобы обработать одну за другой. Те же задачи JavaScript также выполняются одна за другой. , Если первый занимает много времени, то последний должен подождать. , дождитесь завершения предыдущего выполнения, прежде чем продолжить. Теперь, когда мы открываем определенный веб-сайт, мы обычно видим какие-то картинки с фоновыми картинками, потому что некоторые картинки, видео и большие объемы данных на странице занимают очень много времени.Знайте, она пустая~ Так что теперь есть синхронные и асинхронные! ~

  • Синхронные и асинхронные задачи входят в разные среды выполнения, синхронно входят в основной поток и асинхронно записываются в список событий таблицы событий.
  • Когда событие завершено, задача из списка событий помещается в очередь событий очереди событий, ожидая выполнения.
  • После того, как основной поток выполнит все задачи, он проверит очередь событий и, если таковые имеются, вытащит ее и выполнит.
  • Вышеуказанные шаги будут повторяться до тех пор, пока не останется исполняемой задачи, образующей цикл событий;
axios.post('/user', { name: 'fly', age: '30' })
.then(function (response) {
    console.log(response);
 })
console.log('代码执行结束');
  • axios входит в список событий. Начните выполнение основного потока и получите console.log("Конец выполнения кода");
  • Затем выполняется axios и возвращается функция для входа в очередь событий Event Queue;
  • У основного потока нет задачи, и он обращается к очереди событий, чтобы получить ее, и получает функцию обратного вызова для выполнения;

setTimeout

Я считаю, что setTimeout знаком не всем, и его можно использовать в работе, асинхронных функциях и отложенном выполнении~

setTimeout(() => {
    console.log('执行setTimeout');
},3000)
console.log('执行console');

Согласно нашей предыдущей идее, сначала выполнить console.log('выполнить консоль'); затем выполнить console.log('выполнить setTimeout'); ответ правильный, затем снова изменить его:

setTimeout(() => {
    abc();
},3000)
exercise(100000000);//假设有个运动函数,需要时间很长...而且不固定...大于3秒,可能10秒

Затем мы запускаем результаты и обнаруживаем, что console.log('execute setTimeout') не выполняется через 3 секунды;

  • Асинхронная функция setTimeout передается асинхронной задаче и записывает список событий.
  • Основная программа выполняет функцию упражнения, 1 секунда, 2 секунды, 3 секунды... Ожидание.
  • Через три секунды abc() помещается в очередь событий Event Queue и ожидает выполнения, но функция упражнения еще не выполнена, так что просто подождите~
  • Наконец, выполнение завершено, нужно перейти в очередь событий, чтобы найти задачу для выполнения, а abc() входит в основной поток и выполняет ее.

После завершения вышеуказанного процесса мы знаем, что функция setTimeout добавляет задачу для выполнения (abc() в этом примере) в очередь событий через указанное время, и поскольку это однопоточная задача, ее необходимо выполняется одна за другой. Предыдущая задача занимает слишком много времени, поэтому вам остается только ждать, в результате чего реальное время задержки намного превышает 3 секунды. Иногда мы видим форму setTimeout(function(),0); Выполняется ли 0 секунд сразу? не совсем

Тогда его сознание состоит в том, что для входа в Очередь событий не требуется много секунд, и когда основная задача потока будет завершена, он вернется к выполнению. Или предыдущий пример:

setTimeout(() => {
    abc();
},0)
console.log('执行console');
//  1.执行console   2.abc()

Позвольте мне рассказать об этом здесь.На самом деле я видел, что автор сказал, что setTimeout имеет ограничение минимального интервала времени.Стандарт HTML5 составляет 4 мс, и если он меньше 4 мс, он обрабатывается по 4 мс, но минимальный интервал реализуется каждым браузером по-разному. Минимальный интервал для setInterval составляет 10 миллисекунд, то есть интервал менее 10 миллисекунд будет скорректирован до 10 миллисекунд. Сделайте заметку здесь.

setInterval

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

Promise

Вот краткое введение в роль Promise, и я не буду много говорить о деталях (еще много чего можно подытожить...), Объекты Promise используются для асинхронных операций. В реальной разработке мы столкнемся с такой ситуацией:

$.ajax({
    url:www.javascript.com,
    data:data,
    success:() => {
        console.log('第一个数据返回成功!');
        $.ajax({
            url:www.javascript.com,
            data:data,
            success:() => {
                console.log('第二个数据返回成功!');
                ...如果还有再继续
            }
        })
    }
})

Увидев этот код, вы должны быть знакомы с ним. Я думаю, вы уже сталкивались с ним раньше. "Выглядит довольно хорошо, это довольно хорошо~~~"! Я думаю, вы гей, старик очень плохой~, теперь Обещание отправлено Используется:

function abc(url,param){
    return new Promise(function (resolve, reject) {
        request(url, param, function(){
            resolve('数据请求成功了');
        }, reject);
    });
}
abc.then(function(data){
    console.log(date);//'第一个数据请求成功了';
    return new Promise(function (resolve, reject) {
            request(url, param, function(){
                resolve('数据请求成功了');
            }, reject)
           });
}).then(function(){
    console.log(date);//'第二个数据请求成功了';
});

Я не буду здесь больше говорить об использовании Promise.Продолжим нашу тему.Помимо обобщенных синхронных задач и асинхронных задач у нас есть более уточненное определение задач:

  • Задача макроса содержит весь блок кода скрипта, setTimeout, setInterval
  • Обещание микрозадачи, process.nextTick (здесь не описано)

Различные типы задач будут попадать в соответствующую очередь событий Очередь событий, например, setTimeout и setInterval будут попадать в одну и ту же очередь событий. Обещание и process.nextTick войдут в то же самое.

setTimeout(function() {
    console.log('setTimeout');
})
new Promise(function(resolve) {
    console.log('promise');
    resolve();
}).then(function() {
    console.log('then');
})
console.log('console');

Результат выполнения: обещание, консоль, затем setTimeout

  • Этот код входит в основной поток как задача макроса.
  • Сначала см. setTimeout, затем зарегистрируйте его и поместите в очередь событий очереди событий задачи макроса.
  • Далее идет промис, сразу же выполняется новый промис, а функция then распределяется по очереди событий микрозадачи.
  • Когда встречается console.log(), он выполняется немедленно.
  • Выполнение первой задачи макроса на данный момент завершено. Затем мы должны посмотреть, есть ли микрозадачи, да, есть, взять их и выполнить.
  • Первый виток цикла событий закончен, начинаем второй виток цикла, естественно, начиная с макрозадачи Event Queue. Мы нашли callback-функцию, соответствующую setTimeout, в макрозадаче Event Queue и тут же ее выполнили.
  • Исполнение заканчивается.

Связь между циклом событий, макрозадачей и микрозадачей показана на рисунке (здесь я вижу картинку, используемую многими авторами, я тоже туда зайду, спасибо автору картинки):

Затем я получаю кусок кода ниже, который также можно увидеть в Интернете:

console.log('1');

setTimeout(function() {
    console.log('2');
    process.nextTick(function() {
        console.log('3');
    })
    new Promise(function(resolve) {
        console.log('4');
        resolve();
    }).then(function() {
        console.log('5')
    })
})
process.nextTick(function() {
    console.log('6');
})
new Promise(function(resolve) {
    console.log('7');
    resolve();
}).then(function() {
    console.log('8')
})

setTimeout(function() {
    console.log('9');
    process.nextTick(function() {
        console.log('10');
    })
    new Promise(function(resolve) {
        console.log('11');
        resolve();
    }).then(function() {
        console.log('12')
    })
})
附上输出结果:1,7,6,8,2,4,3,5,9,11,10,12

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