Funções assíncronas
Aprenda quando e como executar funções assíncronas no código da sua cena.
Visão geral
A maior parte do código na sua scene é executada de forma síncrona usando uma única thread. Isso significa que os comandos são executados sequencialmente, linha por linha. Cada comando precisa primeiro esperar que o comando anterior termine de ser executado antes de poder começar.
Até mesmo as funções nos systems da sua scene são executadas uma por uma, seguindo uma ordem de prioridade.
Executar o código de forma síncrona garante consistência, pois você sempre pode ter certeza de que saberá a ordem em que os comandos no seu código são executados.
Por outro lado, sua scene precisa ser atualizada muitas vezes por segundo, construindo o próximo frame. Se uma parte do seu código demorar demais para responder, então a thread principal inteira fica bloqueada e isso resulta em taxas de frames com lag.
É por isso que, em alguns casos, você quer que alguns comandos sejam executados de forma assíncrona. Isso significa que você pode iniciar uma tarefa em uma nova thread e, enquanto isso, a thread principal pode continuar executando as próximas linhas de código.
Isso é especialmente útil para tarefas que dependem de serviços externos que podem levar tempo para responder, já que você não quer que esse tempo ocioso de espera pela resposta bloqueie outras tarefas.
Por exemplo:
Ao recuperar dados de uma REST API
Ao realizar uma transação na blockchain
📔 Nota: Tenha em mente que vários frames da sua scene podem ser renderizados antes que a tarefa termine de ser executada. Certifique-se de que o código da sua scene seja flexível o suficiente para lidar com os cenários intermediários enquanto a tarefa assíncrona está sendo concluída.
Executar uma função assíncrona
Marque qualquer função como async para que ela seja executada em uma thread separada da thread principal da scene toda vez que for chamada.
// declarar função assíncrona
async function myAsyncTask() {
// executar as etapas da função
}
// chamar função assíncrona
myAsyncTask()
// o restante do código continua sendo executadoA função executeTask
O executeTask() a função executa uma função lambda de forma assíncrona, em uma thread separada da thread principal da scene. executeTask() permite-nos declarar e executar a função tudo em uma única mesma 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 é concluída. Essa função lambda pode opcionalmente ter entradas mapeadas a partir do que a instrução anterior retorna.
📔 Nota: Geralmente é melhor usar a abordagem executeTask em vez da função then function. Neste exemplo, a scene não será considerada totalmente carregada pelo explorer até que a myAsyncTask() function seja concluída, o que pode afetar os tempos de carregamento. Além disso, se depender demais da função then em vários níveis aninhados, você pode acabar com o que é conhecido como "callback hell", onde o código pode se tornar muito difícil de ler e manter.
Funções PointerEvents e RayCast
Quando sua scene usa um PointerEvent ou um RayCast component, os cálculos de colisões são realizados de forma assíncrona no engine. O engine então retorna um evento de resultados para a scene, que pode chegar um ou vários ticks do game loop depois de quando o evento foi invocado.
Você então precisa criar um system para processar esses resultados no frame em que eles chegarem.
📔 Nota: Se você lidar com cliques por meio da abordagem Register a callback você não precisa criar explicitamente um system para lidar com isso, mas o mesmo ocorre em segundo plano.
Consulte 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 você queira executar esse cálculo em uma função assíncrona.
A instrução await
Um await a instrução força a execução a esperar por uma resposta antes de avançar para a próxima linha de código. await as 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 recuperar dados de uma API externa. A fetch() operação é assíncrona, pois não podemos prever quanto tempo o servidor levará para responder. No entanto, a próxima linha precisa que a saída dessa operação esteja pronta antes de podermos analisá-la como um json. A await instrução aqui garante que a próxima linha só será executada depois que essa operação retornar um valor. Da mesma forma, a response.json() função também é assíncrona, mas a próxima linha precisa que o json seja analisado antes de poder registrá-lo. A segunda await instrução força a próxima linha a ser chamada somente depois que a análise do json for concluída, independentemente de quanto tempo isso leve.
Definir um Timeout para uma chamada de função
Use setTimeout para esperar algum tempo antes que certas linhas de código sejam executadas. Isso leva dois argumentos:
A função a executar
A quantidade de milissegundos a esperar antes de executar essa função
O exemplo abaixo espera 1000 milissegundos (equivalente a 1 segundo) antes de executar uma função simples que registra uma mensagem no console.
O clearTimeout pode ser usado para cancelar a execução de uma setTimeout função que ainda está aguardando para ser executada. Ao criar a setTimeout função, pegue uma referência à função, que você pode então passar para clearTimeout. Nesse caso, a variável intervalId é obtida ao fazer o setTimeout, e então passada para clearTimeout para cancelá-la.
Atualizado