ждать / наблюдать в рамках функции - PullRequest
0 голосов
/ 07 апреля 2020

Я не могу разобраться с этим. Как я могу подождать, пока я == 2 до конца sh, прежде чем продолжить с другими я?

class Observable {
    constructor() {
        this.observers = [];
    }
    subscribe(f) {
        this.observers.push(f);
    }
    unsubscribe(f) {
        this.observers = this.observers.filter(subscriber => subscriber !== f);
    }
    notify(data, options) {
        this.observers.forEach(observer => observer(data));
    }
}

let myObserver = new Observable();

for (let i=0; i <= 2; i++){
    let proc = async function processor(foo) {
        console.log('Processing ' + i + ' ' + foo);

        if (i != 2){
            //await for i = 2 to finish
            //??? <----
        }

        // do other stuff which requires i = 2 
        await new Promise(r => setTimeout(r, i * 1000));
        console.log('Done ' + i);
    }

    myObserver.subscribe(proc);
}

myObserver.notify('Hello');

Я добавил более конкретный пример - может пролить свет на то, что я на самом деле пытаюсь достичь sh. (Используется тот же класс Observable, что и выше)

let allData = {};

let dataProviders = {
    provderA: {
        url: 'http://provder.a.com',
        observer: new Observable(),
        requires: null
    },
    providerB: {
        url: 'http://provder.b.com',
        observer: new Observable(),
        requires: 'providerA'
    }
}

let consumers = {
    consumerX: {
        provider: 'providerA'
    },
    consumerY: {
        provider: 'providerB'
    },
    consumerZ: {
        provider: 'providerB'
    }
}

function getData(providerName) {
    let urlParam = '';

    if (dataProviders[providerName][requires] != null) {
        // (a)wait for providerA / dataProviders[providerName][requires]
        // ??? <----
        urlParam += allData[dataProviders[providerName][requires]]['parameter']
    }

    $.getJSON(dataProviders[providerName][url] + urlParam).done(function (result) {
        allData[providerName] = result;
        dataProviders[providerName][observer].notify(allData)
    });
}

for (const consumer of Object.keys(consumers)) {
    let subscription = function (data) {
        console.log('process data');
        console.log(data)
    }
    dataProviders[consumers[consumer]['provider']].subscribe(subscription);
}

for (const providerName of Object.keys(dataProviders)) {
    getData(providerName);
}

Ответы [ 2 ]

2 голосов
/ 07 апреля 2020

Я подозреваю, что вы ищете

async function getData(providerName) {
    const { url, requires } = dataProviders[providerName];
    let urlParam = '';
    if (requires != null) {
        const requiredData = await new Promise(resolve => {
            dataProviders[requires].observer.subscribe(() => {
                resolve(allData[requires]);
            });
            // getData(requires); ???
        });
        urlParam += requiredData.parameter;
    }

    const result = await $.getJSON(url + urlParam);
    allData[providerName] = result;
    dataProviders[providerName][observer].notify(allData);
}

Вы могли бы упростить подписку на обратный вызов resolve r, если вы уведомили своих наблюдателей с указанием c result, а не allData , Тем не менее, я полагаю, вы могли бы вообще отбросить этот класс Observer и просто использовать обещание, если вы не извлекаете данные несколько раз. Это позволит вам избавиться от магазина allData и просто запомнить обещание, возвращаемое getData, что значительно упростит весь код:

const dataProviders = {
    provderA: {
        url: 'http://provder.a.com',
        promise: null,
        requires: null
    },
    providerB: {
        url: 'http://provder.b.com',
        promise: null,
        requires: 'providerA'
    }
};
function getDataOnce(providerName) {
    const provider = dataProviders[providerName];
    if (provider.promise == null)
        provider.promise = getData(provider);
    return provider.promise;
}
async function getData({ url, requires }) {
    let urlParam = '';
    if (requires != null) {
        const requiredData = await getDataOnce(requires);
        urlParam += requiredData.parameter;
    }

    const result = await $.getJSON(url + urlParam);
    return result;
}

const consumers = {
    consumerX: {
        provider: 'providerA'
    },
    consumerY: {
        provider: 'providerB'
    },
    consumerZ: {
        provider: 'providerB'
    }
};    
for (const consumer of Object.values(consumers)) {
    getDataOnce(consumer.provider).then(data =>
        console.log('process data');
        console.log(data)
    });
}
0 голосов
/ 07 апреля 2020

Здесь вы можете использовать обещание.

async function getData(providerName) {

    if (dataFromAnotherProviderIsNeeded) {
        // wait till promise resolve
        await new Promise( async (resolve) => {
            await getData(anotherProvider);
            // when request is done, resolve
            resolve();
        };
    }

    // Previous request is done 

}

Другой вариант - использовать concat из rx js, чтобы дождаться выдачи первого запроса перед выполнением второго запроса (используя rx js гораздо более мощный, но, возможно, не нужен в простом случае).

...