JavaScript - однопоточный язык, то есть у него один стек, следовательно, только одна комманда может быть выполнена в единицу времени. Но если у тебя только один поток, как у JavaScript, это может привести к серьёзным задержкам. Проблема с однопоточностью решается "асинхронностью". То есть JavaScript использует дополнительные ресурсы браузера или NodeJS или какого-либо другого окружения, кроме собственно основного движка, для того, чтобы иметь возможность что-то делегировать этим ресурсам и не ждать окончания одной операции, чтобы приступить к следующей.
Это реализуется через "цикл событий" ("event loop"):
- Когда функция вызывается, она загружается в стек.
- Но потом она начинает выполняться в "дополнительных ресурсах" пока не выполнится до конца.
- Пока она выполняется "в стороне", другие функции из стека могут быть в него загружены.
- Когда функция выполнена, она возвращается сначала в "очередь на возвращение" ("task queue") и обратно в стек.
Event loop - потому что JavaScript циклом мечется между стеком, и "очередью", проверяя, 1) пустой ли стек, и если стек пустой, то 2) есть ли в очереди то, что нужно возвращать. И если ещё нету, бежит дальше по кругу, если есть - помещает это (то, что первое в очереди) в стек.
И здесь есть большая проблема: часто мы не можем знать, в какой очередности будут выполняться функции. То есть что выполнится первым - то, что идет следующим в коде или то, что вернется из очереди?
Так вот, чтобы избежать синхронности придумали колбеки ("callback"). Колбек - это функция, которая передается в качестве параметра в другую функцию, если нужно, чтобы она была выполнена после той, в которую передана (или в нужном месте внутри). Например:
function callback() {
console.log('I am callback!');
};
let a = 'I am a parameter of anotherFunction!';
function anotherFunction(a, callback) {
console.log(a);
callback();
}
Тогда, если нам важна очередность выполнения, мы должны вкладывать колбек в колбек в колбек и т.д. В этом коде легко запутаться, особенно потому, что переданные функции могут быть описаны совершенно в другом месте, а здесь только вызваны - это называется "ад колбеков".
Чтобы его избежать, придумали (например) промисы ("promises").
Промис - это объект, который "обещает" выполнить то, что внутри. Он принимает функцию, которая имеет параметры resolve и reject, которые, соответственно, вызываются в случае успешного или неуспешного выполнения (вызываются с необходимыми параметрами). То есть, промис не только имеет возвращаемое значение той функции, которая выполнялась внутри него, но и состояние, успешно или нет прошло выполнение. И это состояние можно использовать - в случае неуспешного выполнения - ловить ошибку, добавив к промису через точку catch(...), а в случае успешного - вызывать следующую функцию, добавив к промису через точку then(...). Ну и соответственно, можно промисы цеплять в цепочку один за одним, если принципиально последовательное выполнение определенных функций.
И поскольку я вчера тупил, и не смог написать промис на собеседовании, то вот пример:
let promise = new Promise(function(resolve, request) {
let data = 5 + 3;
resolve(data);
}).then(function(data) {
console log(data + 125);
});
Комментариев нет:
Отправить комментарий