async со стрелочной функцией не работает в react-native

106
27 февраля 2021, 09:50

Что происходит. Не пойму.

Есть метод жизненного цикла компонента в react-native

componentDidMount().

И есть такой код:

class EnterAdditionalData extends Component<Props> {
    constructor(props) {
        super(props);
        this.state = {
            isLoadInfo: false,
        }
    }
    func = async () => {
        for (let i = 0; i < 100000000; i++) {
            console.log(i);
        }
        this.setState({isLoadtInfo: true});
    }
    componentDidMount() {
        this.func();
    }
    render() {
        return <View><Text>Hello</Text></View>
    }
}

Итог: async не работает, т.к. выполняется цикл for (let i = 0; i < 100000000; i++) и соответственно все зависает пока работает цикл. На компоненте зависают все элементы управления. И где тут работа async если программа ждет выполнение метода помеченного async, а не продолжает параллельно выполняться?

А вот если вместо цикла мы указываем

setTimeout(() => {
            this.setState({isLoadInfo: true});
}, 9000);

тогда все работает как надо:

class EnterAdditionalData extends Component<Props> {
    constructor(props) {
        super(props);
        this.state = {
            isLoadInfo: false,
        }
    }
    func = async () => {
        setTimeout(() => {
            this.setState({isLoadInfo: true});
        }, 9000);
    }
    componentDidMount() {
        this.func();
    }
    render() {
        return <View><Text>Hello</Text></View>
    }
}

Здесь async работает как нужно. И программа не останавливается на методе setTimeout() и по прошествии 9 сек компонент рендерится

Что я делаю не так? Заранее спасибо.

Answer 1

Я нашел решение.

Т.к. JavaScript является однопоточным, то это значит что только один блок кода может запускаться за раз. Движок JS обрабатывает код строку за строкой и помещает все в стек, который у него один. Мы не можем использовать цикл без полной блокировки приложения. В данном случае наш цикл является блокирующим кодом, а точнее одним блоком кода.

Чтобы нам помочь JS разрулить эту ситуацию, нужно дать возможность обрабатывать цикл "порциями". А между этими "порциями" JS будет помещать остальной код (например: рендеринг, нажатие на различные элементы интерфейса и т.д.) в стек и выполнять его немедленно, а затем последует следующая "порция" нашего цикла. И так далее, пока не будет закончен весь цикл.

class EnterAdditionalData extends Component<Props> {
    constructor(props) {
        super(props);
        this.state = {
            isLoadInfo: false,
        }
    }
        func = (count, chunksize, checksize, callback, callbackOther) => {
            let i = 0;
            (function chunk() {
                let end = Math.min(i + chunksize, count);
                for (; i < end; ++i) {
                    //Делать что-то во время цикла
                    callback.call(null, i);
                }
                if (i < count) {
                    //Делать что-то между циклами
                    if (i % checksize === 0) {
                        console.log(i);
                        callbackOther.call(null);
                    }
                    setTimeout(chunk, 0);
                } else {
                    //То что выполнится после цикла
                }
            })();
        };
        setstate = () => {
            if (!this.state.isLoadInfo)
                this.setState({isLoadInfo: true});
        };
        componentDidMount() {
            this.func(100000, 100, 10000,
                (i) => {
                //Делать что-то во время цикла
            }, () => {
                this.setstate();
            });
        }
        render() {
            return <View><Text>Hello</Text></View>
        }
    }

checksize - это кол-во итераций через которое будет выполнено ваше условие (в данном случае this.setstate())

P.S. Данный пример с циклом это всего лишь пример того, как долго могут выполняться некоторые участки кода, которые должны выполняться параллельно с остальным кодом. В случае если у вас есть участок кода к которому вы применяете async/await и в нем происходят долгие и сложные вычисления, можно использовать что-то вроде этого примера чтобы пользователи вашего приложения не заметили проблем при навигации по приложению.

И не забывайте очищать setTimeout() при размонтировании компонента в методе жизненного цикла компонента:

componentWillUnmount () {
}

Представленный пример кода отсюда (без моих доработок):

Как сделать неблокирующий код JavaScript?

Вот еще хорошая статья:

Создание неблокирующих функций в JavaScript

READ ALSO
Где ошибка в коде при создании telegraf-bot?

Где ошибка в коде при создании telegraf-bot?

бот должен реагировать на команду /напомни действие в часы:минуты

112
FormatMessage без переносов на новую строку

FormatMessage без переносов на новую строку

Я получаю сообщение об ошибке полученной через GetLastError, и использую FormatMessage для преобразования в читабельный вид (для отладки)

133
CMake: Как добавить qt классы в подпроект?

CMake: Как добавить qt классы в подпроект?

Проект пустой, который создается по умолчанию (в формате qmake)

110
Подсчет количества единичных бит

Подсчет количества единичных бит

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

125