En esta página, se incluyen varias prácticas recomendadas para desarrollar con secuencias de comandos de Google Ads.
Selectores
Filtrar con selectores
Cuando sea posible, usa filtros para solicitar solo las entidades que necesitas. Aplicar los filtros adecuados tiene los siguientes beneficios:
- El código es más simple y fácil de entender.
- La secuencia de comandos se ejecutará mucho más rápido.
Compara los siguientes fragmentos de código:
Enfoque de programación | Fragmento de código |
---|---|
Filtrar con selectores (recomendado) |
var keywords = AdsApp.keywords() .withCondition('Clicks > 10') .forDateRange('LAST_MONTH') .get(); while (keywords.hasNext()) { var keyword = keywords.next(); // Do work here. } |
Filtrar por código (no recomendado) |
var keywords = AdsApp.keywords().get(); while (keywords.hasNext()) { var keyword = keywords.next(); var stats = keyword.getStatsFor( 'LAST_MONTH'); if (stats.getClicks() > 10) { // Do work here. } } |
No se recomienda el segundo enfoque porque intenta recuperar la lista de todas las palabras clave de su cuenta solo para aplicar un filtro a la lista.
Evitar desviar la jerarquía de la campaña
Cuando quieras recuperar entidades en un nivel determinado, usa una colección de la campaña a ese nivel, en lugar de recorrer toda la jerarquía de la campaña. En Además de ser más simple, también tendrá un rendimiento mucho mejor: el sistema no tendrá que leer innecesariamente en todas las campañas y grupos de anuncios.
Compara los siguientes fragmentos de código que recuperan todos los anuncios de tu cuenta:
Enfoque de programación | Fragmento de código |
---|---|
Usa un método de recolección adecuado (recomendado) |
var ads = AdsApp.ads(); |
Recorre la jerarquía (no recomendado) |
var campaigns = AdsApp.campaigns().get(); while (campaigns.hasNext()) { var adGroups = campaigns.next(). adGroups().get(); while (adGroups.hasNext()) { var ads = adGroups.next().ads().get(); // Do your work here. } } |
No se recomienda el segundo enfoque, ya que intenta recuperar datos jerarquías de objetos (campañas, grupos de anuncios), mientras que solo los anuncios son obligatorios.
Usar métodos de acceso superiores específicos
A veces, debes obtener la entidad superior de un objeto recuperado. En este caso, debes usar un método de acceso proporcionado en lugar de recuperar jerarquías completas.
Compara los siguientes fragmentos de código que recuperan los grupos de anuncios que tienen anuncios de texto con más de 50 clics el mes pasado:
Enfoque de programación | Fragmento de código |
---|---|
Usar el método de acceso superior adecuado (recomendado) |
var ads = AdsApp.ads() .withCondition('Clicks > 50') .forDateRange('LAST_MONTH') .get(); while (ads.hasNext()) { var ad = ads.next(); var adGroup = ad.getAdGroup(); var campaign = ad.getCampaign(); // Store (campaign, adGroup) to an array. } |
Recorre la jerarquía (no recomendado) |
var campaigns = AdsApp.campaigns().get(); while (campaigns.hasNext()) { var adGroups = campaigns.next() .adGroups() .get(); while (adGroups.hasNext()) { var ads = adGroups.ads() .withCondition('Clicks > 50') .forDateRange('LAST_MONTH') .get(); if (ads.totalNumEntities() > 0) { // Store (campaign, adGroup) to an array. } } } |
No se recomienda el segundo enfoque, ya que recupera toda la campaña y grupos de anuncios en su cuenta, mientras que solo necesita un subconjunto campañas y grupos de anuncios asociados con tu conjunto de anuncios. El primer enfoque se limita a recuperar solo la colección de anuncios relevante y usa un método adecuado para acceder a sus objetos superiores.
Usa filtros superiores específicos
Para acceder a las entidades de una campaña o un grupo de anuncios específicos, usa un filtrar en el selector en lugar de recuperar y recorrer una jerarquía.
Compara los siguientes fragmentos de código que recuperan la lista de anuncios de texto dentro de una campaña y un grupo de anuncios específicos que tienen más de 50 clics en último lugar mes.
Enfoque de programación | Fragmento de código |
---|---|
Usar filtros de nivel superior adecuados (recomendado) |
var ads = AdsApp.ads() .withCondition('CampaignName = "Campaign 1"') .withCondition('AdGroupName = "AdGroup 1"') .withCondition('Clicks > 50') .forDateRange('LAST_MONTH') .get(); while (ads.hasNext()) { var ad = ads.next(); var adGroup = ad.getAdGroup(); var campaign = ad.getCampaign(); // Store (campaign, adGroup, ad) to // an array. } |
Recorre la jerarquía (no recomendado) |
var campaigns = AdsApp.campaigns() .withCondition('Name = "Campaign 1"') .get(); while (campaigns.hasNext()) { var adGroups = campaigns.next() .adGroups() .withCondition('Name = "AdGroup 1"') .get(); while (adGroups.hasNext()) { var ads = adGroups.ads() .withCondition('Clicks > 50') .forDateRange('LAST_MONTH') .get(); while (ads.hasNext()) { var ad = ads.next(); // Store (campaign, adGroup, ad) to // an array. } } } |
No se recomienda el segundo enfoque, ya que itera en la campaña y el anuncio jerarquía de grupo en su cuenta, mientras que solo necesita un conjunto seleccionado de anuncios, y las campañas y grupos de anuncios superiores. El primer enfoque limita la iteración a la lista de anuncios aplicando un filtro específico para las entidades superiores en el selector.
Usa los IDs para filtrar cuando sea posible.
Cuando filtras por entidades, es preferible filtrarlas por su en lugar de otros campos.
Considera los siguientes fragmentos de código que seleccionan una campaña.
Enfoque de programación | Fragmento de código |
---|---|
Filtrar por ID (recomendado) |
var campaign = AdsApp.campaigns() .withIds([12345]) .get() .next(); |
Filtrar por nombre (menos óptimo) |
var campaign = AdsApp.campaigns() .withCondition('Name="foo"') .get() .next(); |
El segundo enfoque es menos óptimo, ya que filtramos por un campo que no sea de ID.
Filtrar por IDs parentales siempre que sea posible
Cuando selecciones una entidad, filtra por IDs superiores siempre que sea posible. Si confirmas esta acción, y hacer que tus consultas sean más rápidas limitando la lista de entidades que recupera los servidores cuando filtren los resultados.
Considera el siguiente fragmento de código que recupera un grupo de anuncios por su ID. Supongamos que se conoce el ID de la campaña principal.
Enfoque de programación | Fragmento de código |
---|---|
Filtrar por ID de campaña y grupo de anuncios (recomendado) |
var adGroup = AdsApp.adGroups() .withIds([12345]) .withCondition('CampaignId="54678"') .get() .next(); |
Filtrar solo por el ID de grupo de anuncios (menos óptimo) |
var adGroup = AdsApp.adGroups() .withIds([12345]) .get() .next(); |
Si bien ambos fragmentos de código dan resultados idénticos, el costo adicional
si filtras en el fragmento de código 1 con un ID superior (CampaignId="54678")
código más eficiente al restringir la lista de entidades que tiene el servidor
para iterar cuando filtren los resultados.
Usa etiquetas cuando hay demasiadas condiciones de filtrado
Cuando tienes demasiadas condiciones de filtrado, es una buena idea crear una etiqueta para las entidades que procesas y usarla para filtrar tus entidades.
Considera el siguiente fragmento de código que recupera una lista de campañas por su nombre.
Enfoque de programación | Fragmento de código |
---|---|
Usa una etiqueta (recomendado) |
var label = AdsApp.labels() .withCondition('Name = "My Label"') .get() .next(); var campaigns = label.campaigns.get(); while (campaigns.hasNext()) { var campaign = campaigns.next(); // Do more work } |
Cómo compilar selectores complejos (no recomendado) |
var campaignNames = [‘foo’, ‘bar’, ‘baz’]; for (var i = 0; i < campaignNames.length; i++) { campaignNames[i] = '"' + campaignNames[i] + '"'; } var campaigns = AdsApp.campaigns .withCondition('CampaignName in [' + campaignNames.join(',') + ']') .get(); while (campaigns.hasNext()) { var campaign = campaigns.next(); // Do more work. } |
Si bien ambos fragmentos de código te brindan un nivel de rendimiento similar, tiende a generar un código más complejo, ya que la cantidad de condiciones en tu selector aumentará. También es más fácil aplicar la etiqueta a una entidad nueva que editar la secuencia de comandos para incluir una entidad nueva.
Limita la cantidad de condiciones en tu cláusula IN
Cuando se ejecutan secuencias de comandos, un caso de uso común es ejecutar un informe de una lista de entidades. Los desarrolladores suelen lograr esto construyendo un Consulta AWQL que filtra los ID de entidad mediante una cláusula IN. Este enfoque funciona bien cuando la cantidad de entidades es limitada. Sin embargo, a medida que aumenta la longitud de la consulta, el rendimiento de la secuencia de comandos se deteriora debido a dos motivos:
- Una consulta más larga tarda más en analizarse.
- Cada ID que agregas a una cláusula IN es una condición adicional que debes evaluar. por lo que lleva más tiempo.
En esas condiciones, es preferible aplicar una etiqueta a las entidades y, luego, filtrar por LabelId
.
Enfoque de programación | Fragmento de código |
---|---|
Aplicar una etiqueta y filtrar por labelID (recomendado) |
// The label applied to the entity is "Report Entities" var label = AdsApp.labels() .withCondition('LabelName contains "Report Entities"') .get() .next(); var report = AdsApp.report('SELECT AdGroupId, Id, Clicks, ' + 'Impressions, Cost FROM KEYWORDS_PERFORMANCE_REPORT ' + 'WHERE LabelId = "' + label.getId() + '"'); |
Crea una consulta larga con la cláusula IN (no se recomienda) |
var report = AdsApp.report('SELECT AdGroupId, Id, Clicks, ' + 'Impressions, Cost FROM KEYWORDS_PERFORMANCE_REPORT WHERE ' + 'AdGroupId IN (123, 456) and Id in (123,345, 456…)'); |
Actualizaciones de la cuenta
Cambios por lotes
Cuando realiza cambios en una entidad de Google Ads, las secuencias de comandos de Google Ads no ejecutan el cambian de inmediato. En su lugar, intenta combinar varios cambios en lotes para poder emitir una sola solicitud que realice varios cambios. Este enfoque permite que tus secuencias de comandos sean más rápidas y reduce la carga en Google Ads. servidores. Sin embargo, hay algunos patrones de código que obligan a las secuencias de comandos de Google Ads a vacía su lote de operaciones con frecuencia, lo cual hace que su secuencia de comandos se ejecute lentamente.
Considera la siguiente secuencia de comandos que actualiza las ofertas de una lista de palabras clave.
Enfoque de programación | Fragmento de código |
---|---|
Haz un seguimiento de los elementos actualizados (recomendado) |
var keywords = AdsApp.keywords() .withCondition('Clicks > 50') .withCondition('CampaignName = "Campaign 1"') .withCondition('AdGroupName = "AdGroup 1"') .forDateRange('LAST_MONTH') .get(); var list = []; while (keywords.hasNext()) { var keyword = keywords.next(); keyword.bidding().setCpc(1.5); list.push(keyword); } for (var i = 0; i < list.length; i++) { var keyword = list[i]; Logger.log('%s, %s', keyword.getText(), keyword.bidding().getCpc()); } |
Recupera elementos actualizados en un bucle cerrado (no se recomienda) |
var keywords = AdsApp.keywords() .withCondition('Clicks > 50') .withCondition('CampaignName = "Campaign 1"') .withCondition('AdGroupName = "AdGroup 1"') .forDateRange('LAST_MONTH') .get(); while (keywords.hasNext()) { var keyword = keywords.next(); keyword.bidding().setCpc(1.5); Logger.log('%s, %s', keyword.getText(), keyword.bidding().getCpc()); } |
No se recomienda el segundo enfoque, ya que la llamada
keyword.bidding().getCpc()
obliga a las secuencias de comandos de Google Ads a limpiar el setCpc()
y ejecutar solo una operación a la vez. El primer enfoque, si bien
similar al segundo enfoque, tiene el beneficio adicional de admitir el procesamiento
ya que la llamada a getCpc()
se realiza en un bucle independiente del que
Se llama a setCpc()
.
Usa compiladores cuando sea posible
Las secuencias de comandos de Google Ads admiten dos formas de crear objetos nuevos: compiladores y métodos de creación. Los compiladores son más flexibles que los métodos de creación, ya que te brindan acceso al objeto que se crea a partir de la llamada a la API.
Considera los siguientes fragmentos de código:
Enfoque de programación | Fragmento de código |
---|---|
Cómo usar los compiladores (recomendado) |
var operation = adGroup.newKeywordBuilder() .withText('shoes') .build(); var keyword = operation.getResult(); |
Cómo usar métodos de creación (no recomendado) |
adGroup.createKeyword('shoes'); var keyword = adGroup.keywords() .withCondition('KeywordText="shoes"') .get() .next(); |
No se prefiere el segundo enfoque debido a la operación de selección adicional que implica la recuperación de la palabra clave. Además, los métodos de creación también dejaron de estar disponibles.
Sin embargo, ten en cuenta que, si se usan de forma incorrecta, los compiladores pueden impedir que las secuencias de comandos de Google Ads agrupen sus operaciones.
Considera los siguientes fragmentos de código que crean una lista de palabras clave: e imprime el ID de las palabras clave recién creadas:
Enfoque de programación | Fragmento de código |
---|---|
Haz un seguimiento de los elementos actualizados (recomendado) |
var keywords = [‘foo’, ‘bar’, ‘baz’]; var list = []; for (var i = 0; i < keywords.length; i++) { var operation = adGroup.newKeywordBuilder() .withText(keywords[i]) .build(); list.push(operation); } for (var i = 0; i < list.length; i++) { var operation = list[i]; var result = operation.getResult(); Logger.log('%s %s', result.getId(), result.getText()); } |
Recupera elementos actualizados en un bucle cerrado (no se recomienda) |
var keywords = [‘foo’, ‘bar’, ‘baz’]; for (var i = 0; i < keywords.length; i++) { var operation = adGroup.newKeywordBuilder() .withText(keywords[i]) .build(); var result = operation.getResult(); Logger.log('%s %s', result.getId(), result.getText()); } |
No se prefiere el segundo enfoque porque llama a operation.getResult()
dentro del mismo bucle que crea la operación, lo que obliga a las secuencias de comandos de Google Ads a ejecutar una operación a la vez. Si bien el primer enfoque es similar, permite el procesamiento por lotes, ya que llamamos a operation.getResult() en un bucle diferente del que se creó.
Considera usar cargas masivas para actualizaciones grandes
Una tarea común que realizan los desarrolladores es ejecutar informes y actualizar
propiedades (por ejemplo, ofertas de palabras clave) según los valores actuales del rendimiento. Cuando tienes que actualizar una gran cantidad de entidades, las cargas masivas suelen brindar un mejor rendimiento. Por ejemplo, considera las siguientes secuencias de comandos que aumentan el MaxCpc de las palabras clave cuyo TopImpressionPercentage > 0.4
del último mes es el siguiente:
Enfoque de programación | Fragmento de código |
---|---|
Usar la carga masiva (recomendado) |
var report = AdsApp.report( 'SELECT AdGroupId, Id, CpcBid FROM KEYWORDS_PERFORMANCE_REPORT ' + 'WHERE TopImpressionPercentage > 0.4 DURING LAST_MONTH'); var upload = AdsApp.bulkUploads().newCsvUpload([ report.getColumnHeader('AdGroupId').getBulkUploadColumnName(), report.getColumnHeader('Id').getBulkUploadColumnName(), report.getColumnHeader('CpcBid').getBulkUploadColumnName()]); upload.forCampaignManagement(); var reportRows = report.rows(); while (reportRows.hasNext()) { var row = reportRows.next(); row['CpcBid'] = row['CpcBid'] + 0.02; upload.append(row.formatForUpload()); } upload.apply(); |
Seleccionar y actualizar palabras clave por ID (menos óptimo) |
var reportRows = AdsApp.report('SELECT AdGroupId, Id, CpcBid FROM ' + 'KEYWORDS_PERFORMANCE_REPORT WHERE TopImpressionPercentage > 0.4 ' + ' DURING LAST_MONTH') .rows(); var map = { }; while (reportRows.hasNext()) { var row = reportRows.next(); var adGroupId = row['AdGroupId']; var id = row['Id']; if (map[adGroupId] == null) { map[adGroupId] = []; } map[adGroupId].push([adGroupId, id]); } for (var key in map) { var keywords = AdsApp.keywords() .withCondition('AdGroupId="' + key + '"') .withIds(map[key]) .get(); while (keywords.hasNext()) { var keyword = keywords.next(); keyword.bidding().setCpc(keyword.bidding().getCpc() + 0.02); } } |
El segundo enfoque te brinda un rendimiento bastante bueno, pero el primero se prefiere en este caso, ya que
Las secuencias de comandos de Google Ads tienen un límite para la cantidad de objetos que se pueden recuperar o se actualizan en una sola ejecución, y las operaciones de selección y actualización segundo enfoque cuenta para ese límite.
Las cargas masivas tienen límites más altos en términos de la cantidad de entidades que pueden actualizar y el tiempo de ejecución general.
Cómo agrupar tus cargas masivas por campañas
Cuando crees tus cargas masivas, intenta agrupar tus operaciones según el elemento superior. campaña. Esto aumenta la eficiencia y disminuye la posibilidad de que se produzcan conflictos cambios o errores de simultaneidad.
Considera dos tareas de carga masiva que se ejecutan en paralelo. Uno detiene los anuncios de un anuncio group; mientras que el otro ajusta las ofertas de palabras clave. Aunque las operaciones no estén relacionadas, estas pueden aplicarse a entidades del mismo grupo de anuncios (o a dos grupos de anuncios diferentes de la misma campaña). Cuando esto suceda, el sistema bloqueará la entidad superior (el grupo de anuncios o la campaña compartidos), lo que hará que las tareas de carga masiva se bloqueen entre sí.
Las secuencias de comandos de Google Ads pueden optimizar la ejecución en una sola tarea de carga masiva. lo más simple es ejecutar una sola tarea de carga masiva por cuenta en una vez. Si decides ejecutar más de una carga masiva por cuenta, asegúrate de que las cargas masivas funcionen en una lista de campañas mutuamente excluyentes (y sus entidades secundarias) para obtener un rendimiento óptimo.
Informes
Cómo usar los informes para obtener estadísticas
Cuando quieres recuperar grandes cantidades de entidades y sus estadísticas, es común que es mejor usar informes que los métodos estándares de AdsApp. El uso de por los siguientes motivos:
- Los informes te brindan un mejor rendimiento para las consultas grandes.
- Los informes no alcanzarán las cuotas de recuperación normales.
Compara los siguientes fragmentos de código que recuperan los clics, las impresiones, el costo y el texto de todas las palabras clave que recibieron más de 50 clics el mes pasado:
Enfoque de programación | Fragmento de código |
---|---|
Usa informes (recomendado) |
report = AdsApp.search( 'SELECT ' + ' ad_group_criterion.keyword.text, ' + ' metrics.clicks, ' + ' metrics.cost_micros, ' + ' metrics.impressions ' + 'FROM ' + ' keyword_view ' + 'WHERE ' + ' segments.date DURING LAST_MONTH ' + ' AND metrics.clicks > 50'); while (report.hasNext()) { var row = report.next(); Logger.log('Keyword: %s Impressions: %s ' + 'Clicks: %s Cost: %s', row.adGroupCriterion.keyword.text, row.metrics.impressions, row.metrics.clicks, row.metrics.cost); } |
Usa iteradores de AdsApp (no recomendado) |
var keywords = AdsApp.keywords() .withCondition('metrics.clicks > 50') .forDateRange('LAST_MONTH') .get(); while (keywords.hasNext()) { var keyword = keywords.next(); var stats = keyword.getStatsFor('LAST_MONTH'); Logger.log('Keyword: %s Impressions: %s ' + 'Clicks: %s Cost: %s', keyword.getText(), stats.getImpressions(), stats.getClicks(), stats.getCost()); } |
No se prefiere el segundo enfoque, ya que se itera sobre las palabras clave
y recupera las estadísticas, una entidad a la vez. En este caso, los informes tienen un mejor rendimiento, ya que recuperan todos los datos en una sola llamada y los transmiten según sea necesario. Además, las palabras clave recuperadas en el segundo enfoque son
dentro de la cuota de tu secuencia de comandos para el número de entidades recuperadas con
una llamada get()
Usa la búsqueda en lugar del informe
El método de generación de informes se compiló para la infraestructura anterior y arrojará resultados en un formato plano, incluso si usas GAQL. Esto significa que debe transformar los resultados de la consulta para que coincidan con el estilo antiguo, que no es es compatible con todos los campos y agrega sobrecarga a cada llamada.
Te sugerimos que, en su lugar, uses la búsqueda para aprovechar todas las funciones de la los nuevos informes de la API de Google Ads.
Prefiero GAQL en lugar de AWQL.
Aunque AWQL aún se admite en las consultas de informes y las llamadas a withCondition
, se ejecuta a través de una capa de traducción que no tiene compatibilidad total con AWQL real. Para tener el control total de tus consultas, asegúrate de
con GAQL.
Si tienes consultas de AWQL existentes que deseas traducir, tenemos una herramienta de migración de consultas para ayudarte.
No selecciones más filas de las que necesitas
La velocidad de ejecución de los informes (y selectores) se basa en la cantidad total de filas que devuelve el informe, independientemente de si iteras por ellas. Esto significa que siempre debes usar filtros específicos para minimizar el conjunto de resultados tanto como sea posible para que coincida con tu caso de uso.
Por ejemplo, supongamos que deseas encontrar grupos de anuncios con ofertas fuera de un rango específico. Sería más rápido realizar dos consultas separadas, una para las ofertas por debajo del umbral inferior y otra para las ofertas por encima del umbral superior, que recuperar todos los grupos de anuncios y, luego, ignorar los que no te interesan.
Enfoque de programación | Fragmento de código |
---|---|
Cómo usar dos consultas (recomendado) |
var adGroups = [] var report = AdsApp.search( 'SELECT ad_group.name, ad_group.cpc_bid_micros' + ' FROM ad_group WHERE ad_group.cpc_bid_micros < 1000000'); while (report.hasNext()) { var row = report.next(); adGroups.push(row.adGroup); } var report = AdsApp.search( 'SELECT ad_group.name, ad_group.cpc_bid_micros' + ' FROM ad_group WHERE ad_group.cpc_bid_micros > 2000000'); while (report.hasNext()) { var row = report.next(); adGroups.push(row.adGroup); } |
Cómo filtrar desde una búsqueda genérica (no recomendado) |
var adGroups = [] var report = AdsApp.search( 'SELECT ad_group.name, ad_group.cpc_bid_micros' + ' FROM ad_group'); while (report.hasNext()) { var row = report.next(); var cpcBidMicros = row.adGroup.cpcBidMicros; if (cpcBidMicros < 1000000 || cpcBidMicros > 2000000) { adGroups.push(row.adGroup); } } |
Secuencias de comandos de Ad Manager (MCC)
Se prefiere runInParallel en lugar de la ejecución en serie
Cuando escribas secuencias de comandos para las cuentas de administrador, utiliza executeInParallel()
en su lugar.
de ejecución en serie cuando sea posible. executeInParallel()
le brinda a tu secuencia de comandos más tiempo de procesamiento (hasta una hora) y hasta 30 minutos por cuenta procesada (en lugar de 30 minutos combinados para la ejecución en serie). Consulta nuestros límites.
para obtener más información.
Hojas de cálculo
Usa operaciones por lotes cuando actualices hojas de cálculo
Cuando actualices las hojas de cálculo, intenta usar los métodos de operación masiva (por ejemplo, getRange()
) en lugar de los métodos que actualizan una celda a la vez.
Considera el siguiente fragmento de código que genera un patrón fractal en una hoja de cálculo.
Enfoque de programación | Fragmento de código |
---|---|
Actualiza un rango de celdas en una sola llamada (recomendado) |
var colors = new Array(100); for (var y = 0; y < 100; y++) { xcoord = xmin; colors[y] = new Array(100); for (var x = 0; x < 100; x++) { colors[y][x] = getColor_(xcoord, ycoord); xcoord += xincrement; } ycoord -= yincrement; } sheet.getRange(1, 1, 100, 100).setBackgroundColors(colors); |
Actualiza una celda a la vez (no recomendado) |
var cell = sheet.getRange('a1'); for (var y = 0; y < 100; y++) { xcoord = xmin; for (var x = 0; x < 100; x++) { var c = getColor_(xcoord, ycoord); cell.offset(y, x).setBackgroundColor(c); xcoord += xincrement; } ycoord -= yincrement; SpreadsheetApp.flush(); } |
Si bien Hojas de cálculo de Google intenta optimizar el segundo fragmento de código almacenando en caché los valores, su rendimiento sigue siendo bajo en comparación con el primer fragmento debido a la cantidad de llamadas a la API que se realizan.