нативные функции JsValue возвращают, да
но в расте я ожидаю обычные растовские типы, когда фьюча reqwest::get допустим ответила, то я уже беру промайз JsValue который отдал движку при вызове fetch() из js и разрешаю его с каким-то там ответом.. говорю движку и запускаю цикл обработки сообщений движка
нужно бы хранить список запущенных из js нативных асинхронных функций и иметь возможность прибивать их если нужно
когда список пуст и в движке очередь сообщений пуста, то скрипт выполнился..
короче я нагородил TaskList<T> и впринципе удобно.. его можно подключить, следить есть ли очередь, прибивать если нужно и тд
кодишь fetch в отдельном модуле, базу в другом и тд, потом просто их подключаешь и все
ну вот допустим ты реальзуешь fetch API, и делаешь это поверх reqwest. Тогда вывод растовой футуры тебе нужен только лишь для того, что скормить его JS-движку. Так что если ты частично сотрешь типа, перейдя от Future<Output = Vec<u8>> к Future<Output = JsValue>, то твой код никак не пострадает с т.з. type safety, а JoinHandle-ы станут однородными, и ты сможешь спокойно их хранить.
Если тебе не нравится, что тебе придется в футуры добавлять дополнительное преобразование, то это можно решить введением вспомогательного трейта ToJsValue, который будет реализован для всех нужных тебе растовых типов. И потом сделать вспомогательную функцию такого вида:
fn my_spawn<F, T>(fut: F) -> JoinHandle<JsValue>
where T: ToJsValue,
F: Future<Output=T>
{
tokio::task::spawn(fut.map(ToJsValue::to_js_value))
}