¿Cómo hago para que el método list() espere a que se carguen los datos en el constructor antes de que resuelva su promesa a la persona que llama?
import fetch from 'node-fetch'; class Employees { constructor() { if (Employees._instance) { return Employees._instance } Employees._instance = this; this.employees = []; this.dataLoaded = false; this.url = 'https://raw.githubusercontent.com/graphql-compose/graphql-compose-examples/master/examples/northwind/data/json/employees.json'; (async () => { const response = await fetch(this.url); this.employees = await response.json(); this.dataLoaded = true; console.log(`work done: got ${this.employees.length} employees`); })(); } list() { return new Promise((resolve) => { resolve(this.employees.map(m => `${m.firstName} ${m.lastName} (${m.id})`)); }); } } const employees = new Employees(); (async () => { console.log(await employees.list()); })();Recomiendo que el constructor guarde la promesa de la carga de datos en this , y luego la list puede esperar esa promesa:
class Employees() { constructor() { if (Employees._instance) { return Employees._instance } Employees._instance = this; this.employees = []; this.dataLoaded = false; this.url = 'https://raw.githubusercontent.com/graphql-compose/graphql-compose-examples/master/examples/northwind/data/json/employees.json'; this.initPromise = (async () => { const response = await fetch(this.url); this.employees = await response.json(); this.dataLoaded = true; console.log(`work done: got ${this.employees.length} employees`); })(); } async list() { await this.initPromise; return this.employees.map(m => `${m.firstName} ${m.lastName} (${m.id})`)); } } Si la carga aún no ha terminado, la await hará que la list espere el tiempo que sea necesario. Si finalizó la carga, entonces initPromise está en un estado resuelto y la list se reanudará más o menos inmediatamente (cuando se ejecute la cola de microtareas).
Utilice un objeto Deferred .
un diferido representa un trabajo que aún no está terminado
// fetch mock with 3 seconds wait fetch = () => { return new Promise((resolve) => { setTimeout(() => { resolve({ json: () => new Promise((r) => r([ {firstName: 'Arthur', lastName: 'Pym', id: 1}, {firstName: 'August', lastName: 'Barnard', id: 2}, {firstName: 'M.', lastName: 'Poe', id: 3} ])) }); }, 3000); }); } class MyDeferred { resolve = null; reject = null; promise = null; constructor() { this.promise = new Promise((res, rej) => { this.resolve = res; this.reject = rej; }); } } class Employees { deferred = new MyDeferred(); constructor() { if (Employees._instance) { return Employees._instance } Employees._instance = this; this.employees = []; this.dataLoaded = false; this.url = 'https://raw.githubusercontent.com/graphql-compose/graphql-compose-examples/master/examples/northwind/data/json/employees.json'; (async () => { const response = await fetch(this.url); this.employees = await response.json(); this.dataLoaded = true; this.deferred.resolve(); console.log(`work done: got ${this.employees.length} employees`); })(); } list() { return new Promise((resolve) => { this.deferred.promise.then(() => { resolve(this.employees.map(m => `${m.firstName} ${m.lastName} (${m.id})`)); }); }); } } const employees = new Employees(); (async () => { console.log(await employees.list()); })();