Segundo a documentação:
FirstOrDefault: Retorna o primeiro elemento da sequência que atende a uma condição ou um valor padrão especificado se nenhum elemento desse tipo for encontrado.
https://learn.microsoft.com/pt-br/dotnet/api/system.linq.enumerable.firstordefault?view=net-8.0
**FirstOrDefaultAsync:**Retorna de forma assíncrona o primeiro elemento de uma sequência ou um valor padrão se a sequência não contiver elementos.
https://learn.microsoft.com/pt-br/dotnet/api/system.data.entity.queryableextensions.firstordefaultasync?view=entity-framework-6.2.0
A diferença entre FirstOrDefault e FirstOrDefaultAsync está basicamente no retorno, pois FirstOrDefaultAsync retornará uma task por ser assincrono.
FindAsync: Localiza de forma assíncrona uma entidade com os valores de chave primária fornecidos. Se houver uma entidade com os valores de chave primária fornecidos no contexto, ela será retornada imediatamente sem fazer uma solicitação ao repositório. Caso contrário, uma solicitação será feita ao repositório para uma entidade com os valores de chave primária fornecidos e essa entidade, se encontrada, será anexada ao contexto e retornada. Se nenhuma entidade for encontrada no contexto ou no repositório, será retornado nulo.
https://learn.microsoft.com/pt-br/dotnet/api/system.data.entity.dbset.findasync?view=entity-framework-6.2.0
Sobre qual seria mais indicado, vai depender do contexto do seu problema, caso você queira encontrar apenas o primeiro item de uma consulta, use o FirstOrDefault, se precisar mais de um item use o Find. Leve em consideração a necessidade de usar uma função assíncrona como o FindAsync ou FirstOrDefaultAsync.