08.05.2024, 21:25
|
Новичок на форуме
|
|
Регистрация: 08.05.2024
Сообщений: 7
|
|
порядок загрузки скриптов и await async
отдельные скрипты должны выполняться синхронно по очереди
<html><body>
<script src = 'script.js'></script>
<script>console.log("internal script", result)</script>
</body>/<html>
но в script.js
async function func(){instance = await WebAssembly.instantiate ...}
document.currentScript.onload = async function(){
result = await func()
console.log("onload complete")
}
наличие асинхронной функции слегка ломает порядок загрузки скриптов так как встретив await начнётся загрузка следующего скрипта не дождавшись выполнения предыдующего.
Можно ли как-то сломать здесь асинхронный вызов func() чтобы дождаться загрузки и выполнения первого скрипта и только потом продолжить разбирать дальше html и выполнять остальные скрипты по очереди?
Я более менее понимаю как это надо делать правильно, но хочется понять как это сделать неправильно: не меняя все остальные скрипты, проверяя результат промисов или запихивая в колбэки.
А просто затупить до выполнения func() и выполнить всё "синхронно".
|
|
09.05.2024, 03:48
|
|
Тлен
|
|
Регистрация: 02.01.2010
Сообщений: 6,590
|
|
Простой ответ: нет.
Бредовый ответ: наверное можно заернуть какую-то ересь с использованием service-worker: а именно сделать псевдофайл /wait.js, при запросе которого воркер становится остановку и ждёт сообщения о том что wasm загружен, после чего отмирает, и вставить оный сразу после скрипта который должен ждать...
Но это всё такая муть, что куда проще переписать по-нормальному.
__________________
29375, 35
|
|
09.05.2024, 08:48
|
Новичок на форуме
|
|
Регистрация: 08.05.2024
Сообщений: 7
|
|
Нашел всякие deasync, там да, через вебворкеров дожидаются выполнения асинхронных функций, и да, выглядит очень коряво.
Сообщение от Aetae
|
Но это всё такая муть, что куда проще переписать по-нормальному.
|
А если таких скриптов несколько, да ещё и использующих функции друг друга, то тащить дополнительно везде колбэки и руками добавлять всё в некую очередь чтобы они по цепочке именно друг за другом выполнились, а не как попало, при этом "нормальность" как-то тоже как-то немного тускнеет.
При том что толку от этой асинхронной загрузки всё равно практически никакого, пока все по очереди синхронно не загрузятся делать всё равно особо нечего. Но её зачем-то в некоторых местах (wasm) гвоздями прибили намертво.
Или есть какой-то более простой способ синхронизовать порядок загрузки? через модули?
|
|
09.05.2024, 13:53
|
|
Тлен
|
|
Регистрация: 02.01.2010
Сообщений: 6,590
|
|
Наворотить можно, но на само деле ожидание загрузки прям всех асинхронных скриптов по порядку - это редкая задача.
Обычно в каждом скипте нужно только что-то конкретное.
И тогда просто импортируется только то, что нужно и ждётся в каждом скрипте.
Условно:
/a.js
a = promise
/b.js
b = promise(await a)
/c.js
c = promise(await a)
/d.js
d = promise(await a, await c)
....
__________________
29375, 35
Последний раз редактировалось Aetae, 09.05.2024 в 13:55.
|
|
09.05.2024, 23:16
|
Новичок на форуме
|
|
Регистрация: 08.05.2024
Сообщений: 7
|
|
Сообщение от Aetae
|
И тогда просто импортируется только то, что нужно и ждётся в каждом скрипте.
Условно:
....
|
да, спасибо.
Только у встроенных скриптов (которым теперь надо ещё будет объявить type="module"), порядок исполнения от этого не поломается? и надо ещё дополнительно теперь возвращать промисы из них где порядок выполнения нужно соблюдать.
Или awaitы резолвятся ровно в том порядке в каком добавлялись? а порядок исполнения для встроенных скриптов вроде должен соблюдаться (хотя насчёт type="module" не уверен)
|
|
10.05.2024, 02:54
|
|
Тлен
|
|
Регистрация: 02.01.2010
Сообщений: 6,590
|
|
pvv, не особо разобрал твой вопрос но:
Обычные скритпы которые ни от чего не зависят и от которых ничего не зависит - не трогать.
Обычные скрипты от которых кто-то зависит - ставить вверх в нужном порядке.
Скрипты с чем-то асинхронным которые ни от чего не зависят и от которых ничего не зависит - не трогать.
Скрипты с чем-то асинхронным от которых кто-то зависит - возвращать в конце промис ждущий исполнения и имеющий конкретное имя(от которого и будут зависеть последующие). Промис возвращать либо как глобальную переменную в обычном скрипте, либо как экспорт в модуле.
Скрипты с чем-то асинхронным которые от чего-то зависят - await'ить зависимости по имени перед исполнением.
Скрипты с чем-то асинхронным которые от чего-то зависят И от которых кто-то зависит - await'ить зависимости по имени перед исполнением И возвращать в конце промис ждущий исполнения и имеющий конкретное имя(от которого и будут зависеть последующие). Промис возвращать либо как глобальную переменную в обычном скрипте, либо как экспорт в модуле.
Но чтоб совсем не париться - вот тебе на коленке накидал систему работы с асинхронными зависимостями не зависящую от порядка:
{
// top-script.js
this.dependencies = {
table: {},
get(name) {
if (Array.isArray(name)) return Promise.all(name.map(n => this.get(n)));
return this.table[name] ??= dependenciesProxyPromise();
},
set(name, truePromise) {
const existingPromise = this.table[name];
if (existingPromise) {
const attach = existingPromise[dependenciesProxyPromise.attach];
if (!attach) throw new Error(`[duplicate dependency declaration: ${name}]`);
attach(truePromise);
} else {
this.table[name] = truePromise;
}
return this;
},
};
function dependenciesProxyPromise() {
let resolve, reject;
const promise = new Promise((res, rej) => {
resolve = res;
reject = rej;
});
promise[dependenciesProxyPromise.attach] = (truePromise) => {
truePromise.then(resolve, reject);
delete promise[dependenciesProxyPromise.attach];
return promise;
};;
return promise;
}
dependenciesProxyPromise.attach = Symbol('attach');
// просто для удобства
const delay = (ms) => new Promise(r => setTimeout(r, ms));;
// first.js
console.log('first file start');
// ...
const first = async () => {
console.log('first proxy start');
await delay(3000);
console.log('first proxy end');
};
dependencies.set('first', first());
console.log('first file end')
// second.js
console.log('second file start');
async function second() {
console.log('second proxy start');
const third = await dependencies.get('third');
// ...
await delay(1000);
console.log('second proxy end');
}
dependencies.set('second', second());
console.log('second file end');
// main.js
console.log('main file start');
async function main() {
const [ first, second, third ] = await dependencies.get(['first', 'second', 'third']);
// ...
console.log('main file after all dependencies end');
}
main()
console.log('main file end');
// third.js
console.log('third file start');
const third = async () => {
console.log('third proxy start');
await delay(3000);
console.log('third proxy end');
}
// ...
dependencies.set('third', third());
console.log('third file end');
}
__________________
29375, 35
Последний раз редактировалось Aetae, 10.05.2024 в 04:11.
|
|
10.05.2024, 08:55
|
Новичок на форуме
|
|
Регистрация: 08.05.2024
Сообщений: 7
|
|
Огромное спасибо!
|
|
06.06.2024, 20:16
|
Новичок на форуме
|
|
Регистрация: 08.05.2024
Сообщений: 7
|
|
С js более менее разобрался, всё работает, ещё раз спасибо Aetae.
Теперь настала очередь непосредственно webassembly, которого также корежит при вызове асинхронных функций.
int main(){
int x = foo();
bar(x);
}
Если foo() - асинхронная функция импортированная из JS, то bar будет вызван до того как вернётся foo...
И вот с этим уже официально предлагается бороться через https://web.dev/articles/asyncify, во всяком случае так emscripten вроде бы делает.
Что выглядит уже даже более коряво чем идея заклинить выполнение основного потока каким-нибудь воркером и дожидаясь в его выполнения в каком-нибудь Atomics.wait() "синхронно". По ходу ещё оказалось что sharedarraybuffer позапрещали из-за Spectre.
ткните меня, пожалуйста, в какую-нибудь простую, но рабочую в браузере реализацию чего-то такого:
Цитата:
|
наверное можно заернуть какую-то ересь с использованием service-worker: а именно сделать псевдофайл /wait.js, при запросе которого воркер становится остановку и ждёт сообщения о том что wasm загружен, после чего отмирает, и вставить оный сразу после скрипта который должен ждать...
|
|
|
06.06.2024, 20:41
|
|
Тлен
|
|
Регистрация: 02.01.2010
Сообщений: 6,590
|
|
А на кой те вообще в wasm вызывать асинхронные функции? wasm предназначен для оптимизации узких мест. Если у тебя там какая-то асинхронщина - она априори перекроет любые преимущества полученные от wasm на десяток порядков.
Пиши свой асинхронный код на js, а из wasm экспортируй оптимизированные функции для узких мест, а не наоборот.
__________________
29375, 35
|
|
06.06.2024, 22:11
|
Новичок на форуме
|
|
Регистрация: 08.05.2024
Сообщений: 7
|
|
Ну, например, для реализации dlopen, который зовет Webassembly.instatiate. Вот кто мешал всю эту асинхронщину опциональной сделать, а не гвоздями намертво приколачивать.
или fetch какой-нибудь протащить внутрь wasm.
На кой вообще яваскрипт (ну кроме минимальной необходимой обёртки для запуска wasm), если можно всё собрать в wasm
|
|
|
|