Funções Assíncronas
Aprenda quando e como executar funções assíncronas no código da sua scene.
Visão geral
A maior parte do código na tua scene é executada de forma síncrona usando uma única thread. Isso significa que os comandos são executados sequencialmente, linha por linha. Cada comando tem primeiro de aguardar que o comando anterior termine de ser executado antes de poder começar.
Até mesmo as funções nos systems da tua scene são executadas uma a uma, seguindo uma ordem de prioridade.
Executar código de forma síncrona garante consistência, pois podes sempre ter a certeza de que saberás a ordem em que os comandos no teu código são executados.
Por outro lado, a tua scene precisa de ser atualizada muitas vezes por segundo, construindo o próximo frame. Se uma parte do teu código demorar demasiado a responder, então toda a thread principal fica bloqueada e isso resulta em frame rates mais lentos.
É por isso que, em alguns casos, queres que alguns comandos sejam executados de forma assíncrona. Isso significa que podes iniciar uma tarefa e, entretanto, a scene pode continuar a executar o restante código. A scene continua a executar tudo numa única thread, mas enquanto a tarefa assíncrona aguarda uma resposta, o restante código não fica bloqueado.
Isto é especialmente útil para tarefas que dependem de serviços externos que podem demorar a responder, já que não queres que esse tempo de inatividade à espera dessa resposta bloqueie outras tarefas.
Por exemplo:
Ao obter dados de uma REST API
Ao realizar uma transação na blockchain
📔 Observação: Tem em atenção que vários frames da tua scene podem ser renderizados antes de a tarefa terminar de ser executada. Certifica-te de que o código da tua scene é suficientemente flexível para lidar com os cenários intermédios enquanto a tarefa assíncrona está a ser concluída.
Executar uma função async
Marca qualquer função como async para que seja executada de forma assíncrona, sem bloquear o restante código da tua scene enquanto aguarda.
// declarar função async
async function myAsyncTask() {
// executar os passos da função
}
// chamar função async
myAsyncTask()
// o resto do código continua a ser executadoA função executeTask
O executeTask() a função executa uma função lambda de forma assíncrona. executeTask() permite-nos declarar e executar a função tudo numa única instrução.
A função then
O then a função recebe uma função lambda como argumento, que só é executada quando a instrução anterior termina. Esta função lambda pode opcionalmente ter entradas mapeadas a partir do que quer que a instrução anterior devolva.
📔 Observação: Geralmente é melhor usar a executeTask abordagem em vez da then função. Se dependeres demasiado da then função em vários níveis aninhados, podes acabar com o que é conhecido como "callback hell", em que o código pode ficar muito difícil de ler e manter.
Funções PointerEvents e RayCast
Quando a tua scene usa um PointerEvent ou um RayCast component, os cálculos de colisões são realizados de forma async no Engine. O Engine devolve então um evento de resultados para a scene, que pode chegar um ou vários ticks do game loop depois de o evento ter sido invocado.
Depois tens de criar um system para processar estes resultados no frame em que chegam.
📔 Observação: Se tratares os cliques através da Registar um callback abordagem, não precisas de criar explicitamente um system para tratar isto, mas o mesmo acontece em segundo plano.
Veja eventos de clique e raycasting.
💡 Dica: Se o processamento dos resultados de um raycast exigir muitos cálculos (como executar um algoritmo de path-finding), talvez queiras executar esse cálculo numa função assíncrona.
A instrução await
Uma await instrução força a execução a aguardar uma resposta antes de passar para a linha seguinte de código. await instruções só podem ser usadas dentro de um bloco de código async.
O exemplo acima executa uma função que inclui uma fetch() operação para obter dados de uma API externa. A fetch() operação é assíncrona, já que não podemos prever quanto tempo o servidor vai demorar a responder. No entanto, a linha seguinte precisa que o resultado desta operação esteja pronto antes de o podermos analisar como JSON. A await instrução aqui garante que a linha seguinte só será executada quando essa operação tiver devolvido um valor. De forma semelhante, a response.json() função também é assíncrona, mas a linha seguinte precisa que o JSON seja analisado antes de o poder registar. A segunda await instrução força a linha seguinte a ser chamada apenas quando a análise do JSON terminar, independentemente do tempo que demore.
Definir um Timeout para uma chamada de função
Use setTimeout para aguardar algum tempo antes de certas linhas de código serem executadas. Isto recebe dois argumentos:
A função a executar
A quantidade de milissegundos a aguardar antes de executar essa função
O exemplo abaixo espera 1000 milissegundos (equivalente a 1 segundo) antes de executar uma função simples que regista uma mensagem na consola.
O clearTimeout pode ser usado para cancelar a execução de uma setTimeout função que ainda está à espera de ser executada. setTimeout devolve um timer id (um número), que depois podes passar para clearTimeout. Neste caso, a variável timeoutId é obtida ao fazer o setTimeout, e depois passada para clearTimeout para o cancelar.
Atualizado