JavaScript ES2024 : Les nouvelles fonctionnalités qui changent tout

Découvrez ES2024 : Array.fromAsync(), Object.groupBy(), Promise.withResolvers() et les dernières innovations JavaScript.

Olivier Dupuy
07 juin 2025

5243

Vues

0

Commentaires

22

Min de lecture
JavaScript ES2024 : Les nouvelles fonctionnalités qui changent tout

JavaScript ES2024 : L'évolution continue du langage web

ES2024 (ES15) apporte des améliorations significatives à JavaScript avec des fonctionnalités attendues depuis longtemps par la communauté des développeurs.

1. Array.fromAsync() - Création d'arrays asynchrones

Créez des arrays à partir de sources asynchrones de manière élégante :


// Avant ES2024 - approche complexe
async function createAsyncArray(asyncIterable) {
  const result = [];
  for await (const item of asyncIterable) {
    result.push(await processItem(item));
  }
  return result;
}

// ES2024 - Array.fromAsync()
async function* asyncGenerator() {
  yield Promise.resolve(1);
  yield Promise.resolve(2);
  yield Promise.resolve(3);
}

const asyncArray = await Array.fromAsync(asyncGenerator());
console.log(asyncArray); // [1, 2, 3]

// Avec transformation
const processedArray = await Array.fromAsync(
  asyncGenerator(),
  async (x) => x * 2
);
console.log(processedArray); // [2, 4, 6]

// Utilisation avec des APIs
const apiUrls = [
  'https://api.example1.com/data',
  'https://api.example2.com/data',
  'https://api.example3.com/data'
];

const responses = await Array.fromAsync(
  apiUrls,
  async (url) => {
    const response = await fetch(url);
    return response.json();
  }
);

2. Object.groupBy() - Groupement d'objets natif


const users = [
  { name: 'Alice', department: 'Engineering', salary: 75000 },
  { name: 'Bob', department: 'Engineering', salary: 80000 },
  { name: 'Charlie', department: 'Marketing', salary: 65000 },
  { name: 'Diana', department: 'Marketing', salary: 70000 },
  { name: 'Eve', department: 'HR', salary: 60000 }
];

// ES2024 - Object.groupBy()
const groupedByDepartment = Object.groupBy(users, (user) => user.department);
console.log(groupedByDepartment);
/*
{
  Engineering: [
    { name: 'Alice', department: 'Engineering', salary: 75000 },
    { name: 'Bob', department: 'Engineering', salary: 80000 }
  ],
  Marketing: [
    { name: 'Charlie', department: 'Marketing', salary: 65000 },
    { name: 'Diana', department: 'Marketing', salary: 70000 }
  ],
  HR: [
    { name: 'Eve', department: 'HR', salary: 60000 }
  ]
}
*/

// Groupement par ranges de salaire
const groupedBySalary = Object.groupBy(users, (user) => {
  if (user.salary < 65000) return 'Low';
  if (user.salary < 75000) return 'Medium';
  return 'High';
});

// Map.groupBy() pour des clés non-string
const usersByFirstLetter = Map.groupBy(users, (user) => user.name[0]);

3. Promise.withResolvers() - Contrôle manuel des Promises


// ES2024 - Promise.withResolvers()
function createControllablePromise() {
  const { promise, resolve, reject } = Promise.withResolvers();
  
  // Vous pouvez maintenant contrôler la promise de l'extérieur
  setTimeout(() => {
    resolve('Promise resolved after 2 seconds!');
  }, 2000);
  
  return { promise, resolve, reject };
}

// Usage pratique - System de cache avec timeout
class CacheManager {
  constructor() {
    this.cache = new Map();
  }
  
  async get(key, fetcher, ttl = 5000) {
    if (this.cache.has(key)) {
      return this.cache.get(key).promise;
    }
    
    const { promise, resolve, reject } = Promise.withResolvers();
    
    this.cache.set(key, { promise, resolve, reject });
    
    // Timeout
    const timeoutId = setTimeout(() => {
      this.cache.delete(key);
      reject(new Error('Cache timeout'));
    }, ttl);
    
    try {
      const result = await fetcher();
      clearTimeout(timeoutId);
      resolve(result);
      return result;
    } catch (error) {
      clearTimeout(timeoutId);
      this.cache.delete(key);
      reject(error);
      throw error;
    }
  }
}

// Usage
const cacheManager = new CacheManager();
const userData = await cacheManager.get(
  'user-123',
  () => fetch('/api/user/123').then(r => r.json()),
  10000
);

4. String.prototype.isWellFormed() et toWellFormed()


// Vérification et correction des strings Unicode
const wellFormedString = "Hello 👋 World";
const malformedString = "Hello \uD83D World"; // Surrogate pair incomplet

console.log(wellFormedString.isWellFormed()); // true
console.log(malformedString.isWellFormed());   // false

// Correction automatique
const corrected = malformedString.toWellFormed();
console.log(corrected); // "Hello � World" (avec caractère de remplacement)

// Utilisation pratique avec des données externes
function sanitizeUserInput(input) {
  if (!input.isWellFormed()) {
    return input.toWellFormed();
  }
  return input;
}

// Validation d'API
app.post('/api/comments', (req, res) => {
  const comment = req.body.comment;
  
  if (!comment.isWellFormed()) {
    return res.status(400).json({
      error: 'Invalid Unicode in comment text'
    });
  }
  
  // Traitement du commentaire...
});

5. ArrayBuffer.prototype.resize() et transfer()


// Création d'un ArrayBuffer redimensionnable
const buffer = new ArrayBuffer(8, { maxByteLength: 16 });
const uint8Array = new Uint8Array(buffer);

// Remplissage initial
uint8Array.set([1, 2, 3, 4, 5, 6, 7, 8]);
console.log(buffer.byteLength); // 8

// Redimensionnement
buffer.resize(12);
console.log(buffer.byteLength); // 12

// Les nouvelles données sont initialisées à 0
const expandedArray = new Uint8Array(buffer);
console.log(expandedArray); // [1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 0, 0]

// Transfer - déplacement efficace de la propriété
const transferredBuffer = buffer.transfer(16);
console.log(buffer.byteLength); // 0 (buffer original détaché)
console.log(transferredBuffer.byteLength); // 16

// Utilisation pratique - streaming de données
class StreamBuffer {
  constructor(initialSize = 1024) {
    this.buffer = new ArrayBuffer(initialSize, { maxByteLength: initialSize * 10 });
    this.position = 0;
  }
  
  append(data) {
    const needed = this.position + data.byteLength;
    
    if (needed > this.buffer.byteLength) {
      // Redimensionnement automatique
      const newSize = Math.min(
        needed * 2,
        this.buffer.maxByteLength
      );
      this.buffer.resize(newSize);
    }
    
    const view = new Uint8Array(this.buffer, this.position);
    view.set(new Uint8Array(data));
    this.position += data.byteLength;
  }
  
  getContents() {
    return this.buffer.slice(0, this.position);
  }
}

6. Temporal API (Stage 3) - Gestion moderne des dates


// Attention: Temporal est encore en développement (Stage 3)
// Mais voici un aperçu de son utilisation future

// Création de dates précises
const date = Temporal.PlainDate.from('2024-03-15');
const time = Temporal.PlainTime.from('14:30:00');
const dateTime = Temporal.PlainDateTime.from('2024-03-15T14:30:00');

// Calculs de dates intuitifs
const nextWeek = date.add({ days: 7 });
const lastMonth = date.subtract({ months: 1 });

// Comparaisons faciles
const isBefore = date.compare(nextWeek) < 0; // true

// Gestion des fuseaux horaires
const zonedDateTime = Temporal.ZonedDateTime.from('2024-03-15T14:30:00[Europe/Paris]');
const inTokyo = zonedDateTime.withTimeZone('Asia/Tokyo');

// Formatage flexible
const formatted = dateTime.toLocaleString('fr-FR', {
  year: 'numeric',
  month: 'long',
  day: 'numeric'
});

// Durées précises
const duration = Temporal.Duration.from({ hours: 2, minutes: 30 });
const later = time.add(duration); // 17:00:00

Améliorations de Performance

7. Optimisations des Regex et String Matching


// Nouvelles fonctionnalités regex ES2024
const regex = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/g;
const text = "Today is 2024-03-15 and tomorrow is 2024-03-16";

// Utilisation des named groups de manière plus fluide
for (const match of text.matchAll(regex)) {
  const { year, month, day } = match.groups;
  console.log(`Date: ${day}/${month}/${year}`);
}

// Optimisation des recherches de patterns
const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
const emails = [
  'user@example.com',
  'invalid-email',
  'another@test.org',
  'bad@'
];

// Méthode optimisée pour validation en lot
const validEmails = emails.filter(email => emailPattern.test(email));

Intégration avec les Web APIs Modernes

8. Web Streams et ES2024


// Combinaison de Array.fromAsync avec ReadableStream
async function processStream(stream) {
  const reader = stream.getReader();
  
  async function* streamGenerator() {
    try {
      while (true) {
        const { done, value } = await reader.read();
        if (done) break;
        yield value;
      }
    } finally {
      reader.releaseLock();
    }
  }
  
  // ES2024 - traitement élégant du stream
  return await Array.fromAsync(
    streamGenerator(),
    async (chunk) => {
      // Traitement asynchrone de chaque chunk
      return await processChunk(chunk);
    }
  );
}

// Usage avec fetch
const response = await fetch('https://api.example.com/large-dataset');
const processedData = await processStream(response.body);

Bonnes Pratiques ES2024

  • Array.fromAsync() : Parfait pour traiter des collections asynchrones
  • Object.groupBy() : Remplace les implémentations personnelles de regroupement
  • Promise.withResolvers() : Idéal pour les patterns de contrôle complexes
  • String validation : Essentiel pour la sécurité des applications
  • ArrayBuffer dynamique : Optimise la gestion mémoire

Conclusion

ES2024 continue d'améliorer JavaScript avec des fonctionnalités qui résolvent des problèmes concrets des développeurs. Ces ajouts rendent le code plus lisible, plus performant et plus sûr.

Partager cet article
42
12

Commentaires (0)

Rejoignez la discussion

Connectez-vous pour partager votre avis et échanger avec la communauté

Première discussion

Soyez le premier à partager votre avis sur cet article !

À propos de l'auteur
Olivier Dupuy

Développeur passionné et créateur de contenu technique. Expert en développement web moderne avec ASP.NET Core, JavaScript, et technologies cloud.

Profil
Articles similaires
Web Components : standard natif
02 août 2025 0
JavaScript & Frontend
Responsive Design en 2024
01 août 2025 2
JavaScript & Frontend
Next.js 14 : Server Components
31 juil. 2025 6
JavaScript & Frontend
Navigation rapide
Commentaires (0)