Насколько я понял принцип работы Event Loop, при выполнении кода промисы попадают в очередь Microtask queue и затем выполняются поочередно, потому что java script работает в один поток.
Вместе с тем, метод Promise.all() выполняет промисы параллельно. Вот пример кода:
var p1 = new Promise((resolve, reject) => {
setTimeout(resolve, 1000, "one");
});
var p2 = new Promise((resolve, reject) => {
setTimeout(resolve, 1000, "two");
});
var p3 = new Promise((resolve, reject) => {
setTimeout(resolve, 1000, "three");
});
var p4 = new Promise((resolve, reject) => {
setTimeout(resolve, 1000, "four");
});
Promise.all([p1, p2, p3, p4]).then(value => {
console.log(value);
});
Результат выполнения скрипта через 1 секунду: [ 'one', 'two', 'three', 'four' ]
То есть выполнение и правда выглядит параллельно.
Вместо setTimeout() я решил дать промисам долгую задачу и измерить время выполнения каждого промиса.
var p1 = new Promise((resolve, reject) => {
let start = new Date().getTime();
let i = 1;
while (i < 1e10) {
i++;
}
let end = new Date().getTime();
console.log(`p1: ${(end - start)/1000}s`);
resolve(i);
});
var p2 = new Promise((resolve, reject) => {
let start = new Date().getTime();
let i = 1;
while (i < 1e10) {
i++;
}
let end = new Date().getTime();
console.log(`p2: ${(end - start)/1000}s`);
resolve(i);
});
var p3 = new Promise((resolve, reject) => {
let start = new Date().getTime();
let i = 1;
while (i < 1e10) {
i++;
}
let end = new Date().getTime();
console.log(`p3: ${(end - start)/1000}s`);
resolve(i);
});
var p4 = new Promise((resolve, reject) => {
let start = new Date().getTime();
let i = 1;
while (i < 1e10) {
i++;
}
let end = new Date().getTime();
console.log(`p4: ${(end - start)/1000}s`);
resolve(i);
});
Promise.all([p1, p2, p3, p4]).then(value => {
console.log(value);
});
На выходе:
p1: 11.456s
p2: 11.426s
p3: 11.44s
p4: 11.438s
[ 10000000000, 10000000000, 10000000000, 10000000000 ]
Получается, параллельно промисы все же не выполняются. Почему же тогда с setTimeout() получается параллельно?
Promise.all
- НЕ выполняет промисы параллельно, он их вообще не выполняет. Данная функция возвращает новый Promise, который разрешается когда все переданные Promise успешно завершились.
"Запускается" Promise в момент вызова конструктора, при этом функция, которая передается в конструктор выполняется сразу же синхронно, например:
console.log('before one ctr');
var p1 = new Promise((resolve, reject) => {
console.log('one ctr');
setTimeout(resolve, 2000, "one");
});
console.log('before two ctr');
var p2 = new Promise((resolve, reject) => {
console.log('two ctr');
setTimeout(resolve, 1000, "two");
});
console.log('before three ctr');
var p3 = new Promise((resolve, reject) => {
console.log('three ctr');
setTimeout(resolve, 2000, "three");
});
console.log('before four ctr');
var p4 = new Promise((resolve, reject) => {
console.log('four ctr');
setTimeout(resolve, 1000, "four");
});
Promise.all([p1, p2, p3, p4]).then(value => {
console.log(value);
});
В примере выше видно, что сообщения выводятся последовательно, и асинхронность достигается только за счет использования асинхронной функции setTimeout
. Если ее убрать, как это было сделано в примере в вопросе - будет обычное синхронное выполнение кода, которое эквивалентно тому же коду совсем без Promise.
JavaScript код всегда синхронный (выполняется в одном потоке). Асинхронно выполняется исключительно ожидание коллбэка из нативного кода браузера (HTTP запросы, чтение файлов, таймеры и т.д. исполняются в отдельных потоках условного браузера). Результат асинхронного вызова встает с коллбэком в очередь - цикл событий.
В итоге, нагрузив синхронный поток исполнения JavaScript вы на корню убили асинхронность, так как результаты и коллбэки просто не могут поступить на исполнение.
const sleep = (timeout = 1000) => new Promise(resolve => setTimeout(resolve, timeout, timeout));
const log = (timeout) => console.log('Finished', timeout);
sleep(3).then(log)
sleep(1).then(log)
sleep(0).then(log)
Finished 1
Finished 0
Finished 3
Promise.all позволяет запустить на ожидание коллбека параллельное сразу несколько промисов. Это его основное отличие от конструкции async/await.
const logAsync = async (timeout = 1000) => {
console.log('Finished async', await sleep(timeout));
}
(async function() {
await logAsync(3);
await logAsync(1);
await logAsync(0);
})();
Finished async 3
Finished async 1
Finished async 0
Promise.all срабатывает вместе с последним разрешенным промисом - именно это обеспечивает параллельное ожидание коллбеков. Браузер не ждет исполнения промисов поочередно и сразу перескакивает на новый из массива.
(async function() {
console.time('Promise(all)');
await Promise.all([sleep(3), sleep(1), sleep(0)]);
console.timeEnd('Promise(all)');
})();
Promise(all): 3.877197265625ms
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Чтобы когда плагин включен все работало даже после перезагрузки страницы и отменял изменения после выключения
Пожалуйста, помогите дописать код, чтобы двоеточие в часах мигало, а время обновлялось без перезагрузки страницы
Допустим есть строка qwerty#1 2#qwe#qwe 33#qwe_ty###23#dfg#q==w qwertyuiop #qwer