Cannot read property 'find' of undefined, dexie async await

122
29 июня 2019, 12:30

Проблема возникает из-за того, что получение данных из бд происходит медленно, без async\await получается, что чтение из бд слишком медленное.

В componentWillMount() вылезает ошибка Cannot read property 'find' of undefined, потому что getfieldsets() не успевает отработать к этому времени (как я понимаю)

async function fieldsetsWork(){
    //объявление переменных
    var k=0;
    var string = '';
    var def = getFields().map((it,i)=>({
            name:it.name,
            hidden: false,}));
    var stringDef ='';
    for (var i=0;i<def.length;i++){
        stringDef = stringDef + def[i].name;
    }
    // проверка на существование филдсетов пользователя
    var pushDbUser = Dexie.async(function* (){
        try {
            var p = yield db.table('fieldsets').each(function(element){
                if (element.f_Uname.includes(global.currentUser.value.login.toString())){
                    fieldsets_.push(element);
                    k++;
                }});
            yield p;
            yield console.log('null',fieldsets_);
            yield console.log(fieldsets_[0]);
        } finally { return 0; }
    })
    await pushDbUser().catch(e => console.error(e));

    // проверка версии
    if (k !== 0){
        for (var i=0;i<fieldsets_[0].data.length;i++){
        string = string +fieldsets_[0].data[i].name; }
        if (string == stringDef){ k = k;
        }else k = 0;
    }; 
    await console.log(k);
    // если нет филдсетов добавляем дефолтные
    var pushFDB = Dexie.async(function* (){
        try {
            var p = yield db.table('fieldsets').each(element =>{
            console.log(element)
                if (element.f_Uname.includes('default')){
                fieldsets_.push(element);
                console.log(element);
            }})
            yield p;
            yield console.log('null2',fieldsets_);
            yield console.log(fieldsets_[0]);
            yield console.log('0');
        } finally { return 0; }
    })
    if (k===0){
        await console.log('k=0')
        await pushFDB().catch(e => console.error(e));
        }
    await localStorage.setItem('requirements_fieldsets', JSON.stringify(fieldsets_))
    var p = await fieldsets_.forEach(fieldset=>
        fieldset.data.forEach(field=> field.def = getFields().find(it=> it.name===field.name)));
    fieldsets =  p;
     return  fieldsets_;
}
fieldsetsWork();

export function getFieldsets(force){
    if(force){
        const fieldsets_ = fieldsetsWork(); //JSON.parse(localStorage.getItem('requirements_fieldsets'));
        fieldsets_.forEach(fieldset=>
            fieldset.data.forEach(field=> field.def = getFields().find(it=> it.name===field.name)));
        fieldsets = fieldsets_
    }
    return fieldsets
}

componentWillMount(){
        this.setState(old=>({
            ...old,
            fieldset: getFieldsets().find(it=>it.favourite)
        }));
    }
Answer 1

У вас есть два варианта, при данной структуре организации кода.

Вызвать await fieldsetsWork(). Тогда остальная часть кода не будет выполняться, будет ожидать. На самом деле не очень хороший вариант.

async function fieldsetsWork(){
    //объявление переменных
    var k=0;
    var string = '';
    var def = getFields().map((it,i)=>({
            name:it.name,
            hidden: false,}));
    var stringDef ='';
    for (var i=0;i<def.length;i++){
        stringDef = stringDef + def[i].name;
    }
    // проверка на существование филдсетов пользователя
    var pushDbUser = Dexie.async(function* (){
        try {
            var p = yield db.table('fieldsets').each(function(element){
                if (element.f_Uname.includes(global.currentUser.value.login.toString())){
                    fieldsets_.push(element);
                    k++;
                }});
            yield p;
            yield console.log('null',fieldsets_);
            yield console.log(fieldsets_[0]);
        } finally { return 0; }
    })
    await pushDbUser().catch(e => console.error(e));

    // проверка версии
    if (k !== 0){
        for (var i=0;i<fieldsets_[0].data.length;i++){
        string = string +fieldsets_[0].data[i].name; }
        if (string == stringDef){ k = k;
        }else k = 0;
    }; 
    await console.log(k);
    // если нет филдсетов добавляем дефолтные
    var pushFDB = Dexie.async(function* (){
        try {
            var p = yield db.table('fieldsets').each(element =>{
            console.log(element)
                if (element.f_Uname.includes('default')){
                fieldsets_.push(element);
                console.log(element);
            }})
            yield p;
            yield console.log('null2',fieldsets_);
            yield console.log(fieldsets_[0]);
            yield console.log('0');
        } finally { return 0; }
    })
    if (k===0){
        await console.log('k=0')
        await pushFDB().catch(e => console.error(e));
        }
    await localStorage.setItem('requirements_fieldsets', JSON.stringify(fieldsets_))
    var p = await fieldsets_.forEach(fieldset=>
        fieldset.data.forEach(field=> field.def = getFields().find(it=> it.name===field.name)));
    fieldsets =  p;
     return  fieldsets_;
}
await fieldsetsWork();

export function getFieldsets(force){
    if(force){
        const fieldsets_ = fieldsetsWork(); //JSON.parse(localStorage.getItem('requirements_fieldsets'));
        fieldsets_.forEach(fieldset=>
            fieldset.data.forEach(field=> field.def = getFields().find(it=> it.name===field.name)));
        fieldsets = fieldsets_
    }
    return fieldsets
}

componentWillMount(){
        this.setState(old=>({
            ...old,
            fieldset: getFieldsets().find(it=>it.favourite)
        }));
    } 

Есть другой вариант, получше. Не вызывать отдельно fieldsetsWork, а запустить getFieldsets с параметром force=true. Также переделать fieldsetsWork на асинхронную.

async function fieldsetsWork(){
    //объявление переменных
    var k=0;
    var string = '';
    var def = getFields().map((it,i)=>({
            name:it.name,
            hidden: false,}));
    var stringDef ='';
    for (var i=0;i<def.length;i++){
        stringDef = stringDef + def[i].name;
    }
    // проверка на существование филдсетов пользователя
    var pushDbUser = Dexie.async(function* (){
        try {
            var p = yield db.table('fieldsets').each(function(element){
                if (element.f_Uname.includes(global.currentUser.value.login.toString())){
                    fieldsets_.push(element);
                    k++;
                }});
            yield p;
            yield console.log('null',fieldsets_);
            yield console.log(fieldsets_[0]);
        } finally { return 0; }
    })
    await pushDbUser().catch(e => console.error(e));

    // проверка версии
    if (k !== 0){
        for (var i=0;i<fieldsets_[0].data.length;i++){
        string = string +fieldsets_[0].data[i].name; }
        if (string == stringDef){ k = k;
        }else k = 0;
    }; 
    await console.log(k);
    // если нет филдсетов добавляем дефолтные
    var pushFDB = Dexie.async(function* (){
        try {
            var p = yield db.table('fieldsets').each(element =>{
            console.log(element)
                if (element.f_Uname.includes('default')){
                fieldsets_.push(element);
                console.log(element);
            }})
            yield p;
            yield console.log('null2',fieldsets_);
            yield console.log(fieldsets_[0]);
            yield console.log('0');
        } finally { return 0; }
    })
    if (k===0){
        await console.log('k=0')
        await pushFDB().catch(e => console.error(e));
        }
    await localStorage.setItem('requirements_fieldsets', JSON.stringify(fieldsets_))
    var p = await fieldsets_.forEach(fieldset=>
        fieldset.data.forEach(field=> field.def = getFields().find(it=> it.name===field.name)));
    fieldsets =  p;
     return  fieldsets_;
}
fieldsetsWork();

export async function getFieldsets(force){
    if(force){
        const fieldsets_ = await fieldsetsWork(); //JSON.parse(localStorage.getItem('requirements_fieldsets'));
        fieldsets_.forEach(fieldset=>
            fieldset.data.forEach(field=> field.def = getFields().find(it=> it.name===field.name)));
        fieldsets = fieldsets_
    }
    return fieldsets
}

componentWillMount(){
        this.setState(old=>({
            ...old,
            fieldset: await getFieldsets(true).find(it=>it.favourite)
        }));
    }
READ ALSO
Изменение типа данных у элементов со свойством contentEditable со строки на число

Изменение типа данных у элементов со свойством contentEditable со строки на число

Необходимо задать тип вводимых данных - число, но не срабатываетКак исправить?

137
Анимация перехода на другую страницу React

Анимация перехода на другую страницу React

Пытаюсь сделать анимацию перехода на другую страницу следующим образом: Для начала я обернул в HashRouter мой контейнер, который меняется при...

145
Как выполнить функцию после нескольких AJAX ( количество ajax неизвестно )?

Как выполнить функцию после нескольких AJAX ( количество ajax неизвестно )?

Как после получения ответов сервера от всех AJAX, запустить функцию? Количество AJAX запросов неизвестно, всегда может быть разнымНо нужно дождаться...

114
Смена цвета меню JavaScript

Смена цвета меню JavaScript

Как сделать, чтобы при нажатии на любое подменю, цвет меню менялся?

126