在功能内等待/观察

时间:2020-04-07 09:27:50

标签: javascript async-await observable

我无法解决这个问题。 我如何等待i == 2完成再继续其他我的工作?

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');

我添加了一个更具体的示例-可能会阐明我实际尝试实现的目标。 (使用与上述相同的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 个答案:

答案 0 :(得分:2)

我怀疑您正在寻找

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而不是result通知观察者,则可以简化allData r回调的订阅。但是,如果您不多次获取数据,我想您可以完全放弃该Observer类,而仅使用Promise。这样一来,您就可以摆脱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)
    });
}

答案 1 :(得分:0)

您可以在此处使用诺言。

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 

}

另一种选择是使用rxjs中的concat等到第一个请求发出之前,再执行第二个请求(使用rxjs功能更强大,但在简单情况下可能不需要)。