#javascript
#javascript
Вопрос:
Может быть, это ситуация с асинхронностью / ожиданием, но я думал, что асинхронность предназначена в основном для вызовов api (?)
Как дождаться завершения длинного цикла, например:
let x;
for (i = 1, i < 10000000000000000, i ) {
x = (i * 99999);
}
console.log(x);
Комментарии:
1. Здесь нет асинхронной операции. Цикл выполняется синхронно, поэтому вы «ждете», но просто не можете ничего сделать в той же среде выполнения, пока это не закончится. Обратите внимание, что все выполнение должно будет подождать этого, больше ничего не сработает.
2. «Как вы ждете завершения длинного цикла» Я обычно пью кофе
3. @BenCoupe ответ: да
4. @Cid это немного вводит в заблуждение, поскольку асинхронные функции обрабатываются синхронно до тех пор, пока не встретится либо an
await
, либо areturn
. В этот момент они откладывают исполнение и дают обещание. Soasync function() { doHeavySynchronousOperation() }
заблокирует поток доdoHeavySynchronousOperation
завершения, и только тогда вы получите обещание, которое разрешитundefined
.5. Предполагая, что пример сильно упрощен (полученное число намного превышает максимальное число, которое может представить JS), и у вас действительно трудоемкая задача, делегируйте ее веб-работнику.
Ответ №1:
Я думал, что асинхронность предназначена в основном для вызовов api (?)
Есть два разных понятия, связанных со async
словом:
async/await
синтаксический сахар функций для получения результатов обещаний синхронным образом- реальное асинхронное поведение Вызовы API XHR, отложенное выполнение, обработка событий
async/await
функция не делает выполнение вашей функции асинхронным автоматически.
const foo = async (i) => { console.log('foo running', i); return i == 0 ? 42 : await foo(i-1); };
console.log('foo before')
foo(5)
.then(x => console.log('foo', x))
console.log('foo after')
// foo before
// foo running 5
// foo running 4
// foo running 3
// foo running 2
// foo running 1
// foo running 0
// foo after
// foo 42
Javascript является однопоточным, все параллельные задачи должны быть разделены на асинхронные блоки, чтобы иметь возможность работать другим.
Итак, вы должны разделить цикл синхронизации на множество асинхронных частей, чтобы не зависнуть.
Например (я уменьшаю параметры, чтобы не было слишком много времени для ожидания):
async function calcX() {
let x = 0;
function iteration(i) {
x = (i * 99999);
if ( i >= 10000) return Promise.resolve(x);
return new Promise((resolve) => {
setTimeout(() => iteration(i).then(resolve), 0);
// or requestAnimationFrame
});
}
return await iteration(1);
}
const start = Date.now();
calcX()
.then(x => console.log(x, Date.now() - start), err => console.error(err));
// 4999450005000 42465
Это может быть слишком медленно, если вы помещаете каждую итерацию в цикл событий. Таким образом, вы можете оптимизировать его, объединив их (см. Ответ @Steve’s)
Или используйте WebWorker для выполнения тяжелой задачи синхронизации
Комментарии:
1. » Определенно, нет. Каждый setTimeout или addEventListener в вашем коде также является асинхронным «. но не совсем так, как асинхронная функция, и эти два не имеют ничего общего с promises . Таким образом, пока они асинхронны, это своего рода концепция, отличная от той, которую вы будете использовать
async
в коде.
Ответ №2:
Вы можете преобразовать длительно работающие синхронные функции в асинхронные функции, проверив, прошло ли заданное количество времени, а затем вернуться к функции позже (достигается в этом примере с помощью setTimeout
):
var lastBreak = Date.now()
function takeABreak() {
return new Promise(resolve=>setTimeout(resolve));
}
async function maybeTakeABreak() {
if (Date.now() - 17 > lastBreak) {
lastBreak = Date.now();
await takeABreak();
}
}
async function myLongLoop() {
let x = 0;
for (let i = 1; i < 100000000000000; i ) {
await maybeTakeABreak();
x = (i * 99999);
if (!(i%1000000)) {
console.log(i);
// alternatively you could run `await takeABreak();` here
}
}
return x;
}
myLongLoop().then(x=>console.log(x));