Как мне предотвратить событие, пока код не будет выполнен через импорт/экспорт?

=================== Обновление прогресса ====================

Я сделал свою первую асинхронную функцию в соответствии с учебником Мозилла и еще один. Тем не менее, это не могло предотвратить событие, как я ожидал. Он накапливается, когда я нажимаю несколько раз, прежде чем весь код будет выполнен.

Как мне предотвратить событие, пока код не будет выполнен через импорт/экспорт?

Я ожидаю, что использую асинхронность и обещаю отключить событие до тех пор, пока весь код не будет выполнен, и именно так я использую обратный вызов, например этот пример CodePen.

Кроме того, я не могу полностью понять концепцию Async и Promise. Я думаю, что Async + Promise function отделяет код сам по себе, например, закладку книги в реальной жизни? Очень сложно понять, что происходит внутри кода.

Может ли кто-нибудь объяснить мне, как асинхронность и обещание работают в коде и предотвращают событие?

Это результат, который я сделал до сих пор:

class Async {
    constructor(elem) {
        this.elem = document.querySelectorAll(elem)
        this.flag = true;
        this.selector(this.elem, 'click');
    }
    selector(node, eventName) {
        node.forEach(item => {
            item.addEventListener(eventName, (e) => this.group(e))
        })
    }
    waiting() {
        if (this.flag) {
            this.flag = false;
            return new Promise(resolve => {
                setTimeout(() => {
                    resolve(console.info('waiting . . .'))
                }, 2000)
            })
        }
    }
    result() {
        console.info('test');
        this.flag = true;
    }
    async group(e) {
        const a = await this.waiting();
        const b = await this.result();
    }
}
const async = new Async('.button');


=================== Оригинальный вопрос ===================

Я разделяю блоки кода с помощью импорта/экспорта в Node js, чтобы они выглядели четче при рефакторинге.

Проблема заключается в том, что логический флаг с именем this.flag не предотвращает переопределение события, когда я передаю его в init.js в качестве параметра, подобного этому:

Как мне предотвратить событие, пока код не будет выполнен через импорт/экспорт?

Сначала посмотрите код:

// =================== init ===================
'use strict';
import Terminal from './terminal.js';
import Touch from './touch.js';
export const slider = (function() {
    class Slider {
        constructor(elem) {
            this.elem = document.querySelector(elem);
            this.flag = false;
            this.terminal = new Terminal(this.elem);
            this.touch = new Touch(this.elem);
            this.terminal.insert(this.elem, 'click', this.touch.clicked.bind(this.touch));
        }
        wait(flag, callback) {
            flag = false; // the boolean can't prevent the event overriding right now.
            let bound = callback.bind(this);
            console.info('waiting . . .');
            setTimeout(bound, 1000, flag);
        }
        done(flag) {
            console.info('done');
            flag = true;
        }
    }
    return {
        init: new Slider('.contents')
    }
}())

// =================== terminal.js ===================
export default class Terminal {
    constructor(elem) {
        this.elem = elem;
    }
    insert(node, eventName, callback) {
        node.addEventListener(eventName, callback);
    }
}

// =================== touch.js ===================
import {slider} from './a.js';
export default class Touch {
    constructor(elem) {
        this.elem = elem;
        this.flag = true;
    }
    clicked(e) {
        if (this.flag) {
            console.info(`clicked`);
            let slide = slider;
            slide.init.wait(this.flag, slide.init.done);
        }
    }
}

Но странно то, что когда я заменяю обе функции wait() и result() на touch.js, это предотвращает событие, пока не завершится обратный отсчет.

// touch.js
wait(callback) {
    this.flag = false;
    let bound = callback.bind(this);
    console.info('waiting . . .');
    setTimeout(bound, 1000);
}
done(flag) {
    console.info('done');
    this.flag = true;
}

Я хотел бы знать, почему флаг не может предотвратить событие, когда он передается другому js file, и как сделать так, чтобы он временно отключал событие.

Зачем вам нужно, чтобы класс был обернут в IIFE в модульной системе?

El. 15.07.2019 15:00

@Эл. Для двойной защиты? На самом деле ИДК. Я новичок в JS и хотел создать свой собственный стиль структуры.

sniffingdoggo 15.07.2019 15:06

Когда вы создаете модуль в JS на низком уровне во время компиляции, он будет обернут в IIFE, и использование IIFE внутри модулей не нужно. Если вы хотите провести событие для завершения других процессов, вам нужно использовать Async/Await или pormise.

El. 15.07.2019 15:43

Нет, нет необходимости в IIFE. Просто используйте асинхронное программирование

El. 15.07.2019 16:14
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
4
4
390
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Получил решение. Добавление функций ожидания в логический флаг работает.

class Async {
    constructor(elem) {
        this.elem = document.querySelectorAll(elem)
        this.flag = true;
        this.selector(this.elem, 'click');
    }
    selector(node, eventName) {
        node.forEach(item => {
            item.addEventListener(eventName, (e) => this.group(e))
        })
    }
    waiting() {
        return new Promise(resolve => {
            setTimeout(() => {
                resolve(console.info('waiting . . .'))
            }, 1000)
        })
    }
    result() {
        console.info('test');
        this.flag = true;
    }
    async group(e) {
        // console.info(this.flag);
        if (this.flag) {
            this.flag = false;
            console.info('test');
            const a = await this.waiting();
            const b = await this.result();
        }

    }
}
const async = new Async('.button');

Как правило, лучший способ — отключить кнопку после нажатия и показать какой-нибудь счетчик, чтобы обеспечить визуальную обратную связь с пользователем.

Tarun Lalwani 17.07.2019 18:33
Ответ принят как подходящий

Объяснение

Вообще говоря

  • Шаблон async/await был представлен в ES2017 JavaScript и является синтаксическим сахаром для более старых промисов.
  • Некоторые старые браузеры не поддерживают async/await
  • async — это новый способ сказать return Promise((resolve) => { ... }).
  • await является аналогом async и более новым способом сказать .then(result => { ... }).
    • await можно использовать только в функциях, помеченных как async
  • try/catch является аналогом .catch(error => { ... }). На самом деле это не ново, но вы можете использовать его в этом контексте.

Вы можете узнать больше о async/awaitздесь

Код

Я внес небольшие изменения в ваш код, чтобы он имел больше смысла и написал несколько комментариев, чтобы вы понимали все, что здесь происходит.

class Async {
    constructor(elem) {
        this.elem = document.querySelectorAll(elem)
        this.isRunning = false; // <-- Rename the flag variable to something more meaningful
        this.selector(this.elem, 'click');
    }
    selector(node, eventName) {
        node.forEach(item => {
            item.addEventListener(eventName, (e) => this.group(e))
        })
    }
    waiting() {
        return new Promise((resolve, reject) => { // <-- Move the Promise to here so that every codepath returns something
            if (!this.isRunning) {
                this.isRunning = true;
                console.info('Waiting ... '); // <-- Move the waiting before the timeout, because inside it is not actually waiting, its rather done

                setTimeout(() => { // <-- setTimeout runs the provided function after the provided time in milliseconds elapsed
                    this.isRunning = false; // <-- Switch the isRunning after the timeout, because that makes more sense (because now it is not running anymore)
                    resolve('Done'); // <-- Change the text to done and actually resolve it (eg. remove the console.info)
                }, 2000)
            } else {
                reject('There is already a button function running'); // <-- reject is like throwing an error
            }
        })
    }
    result() {
        console.info('test');
    }
    async group(e) {
        try {
            const a = await this.waiting(); // <-- Assigns 'Done' to the variable a
            console.info(a); // <-- prints the message

            this.result(); // <-- prints 'test' immidiatly after the above console.info
        } catch (error) {
            console.info(error); // <-- Prints the reject message in case the button is already running
        }

        /* group could also be written with the old syntax like this:

        this.waiting().then(result => {
            console.info(result); // Will print "Done" after 2000 milliseconds

            this.result(); // Will print test instantly after the above console.info(). You dont need to await it, because it is not an async function
        }).catch(error => {
            console.info(error); // Will print the reject message in case the button is already running
        });

        */
    }
}
const asyncButton = new Async('.button'); // <-- Don't use async as a variable name. It's a reserved keyword

Пример запуска

Это снова тот же код, но без комментариев, так что вы можете протестировать его прямо здесь, на StackOverflow.

class Async {
    constructor(elem) {
        this.elem = document.querySelectorAll(elem)
        this.isRunning = false;
        this.selector(this.elem, 'click');
    }
    selector(node, eventName) {
        node.forEach(item => {
            item.addEventListener(eventName, (e) => this.group(e))
        })
    }
    waiting() {
        return new Promise((resolve, reject) => { 
            if (!this.isRunning) {
                this.isRunning = true;
                console.info('Waiting ... '); 
                
                setTimeout(() => { 
                    this.isRunning = false;
                    resolve('Done');
                }, 2000)
            } else {
                reject('There is already a button function running'); 
            }
        })
    }
    result() {
        console.info('test');
    }
    async group(e) {
        try {
          const a = await this.waiting(); 
          console.info(a); 
          this.result();
        } catch(error) {
          console.info(error);
        }
    }
}
const asyncButton = new Async('.button');
<button class = "button">Test</button>

Итак, синтаксис promise и async/await похож на синтаксис prototype и class, я сразу понял? Синтаксический сахар обещания?

sniffingdoggo 23.07.2019 15:48

да. Это синтаксический сахар. Но имейте в виду, что некоторые старые браузеры поддерживают только промисы. А некоторые браузеры еще старше (и Internet Explorer) даже не поддерживают промисы. Обновил мой ответ этим объяснением @sniffingdoggo

MauriceNino 23.07.2019 15:49

Оооооооооооооооооооооооооооооооооооооооооооооооооооооооо уже наконец я понял на 100%. Спасибо за подробный ответ :-)

sniffingdoggo 23.07.2019 15:55

Нет проблем, рад, что смог помочь! Если у вас есть еще вопросы, не стесняйтесь спрашивать! @sniffingdoggo

MauriceNino 23.07.2019 15:56

Другие вопросы по теме