=================== Обновление прогресса ====================
Я сделал свою первую асинхронную функцию в соответствии с учебником Мозилла и еще один. Тем не менее, это не могло предотвратить событие, как я ожидал. Он накапливается, когда я нажимаю несколько раз, прежде чем весь код будет выполнен.
Я ожидаю, что использую асинхронность и обещаю отключить событие до тех пор, пока весь код не будет выполнен, и именно так я использую обратный вызов, например этот пример 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, и как сделать так, чтобы он временно отключал событие.
@Эл. Для двойной защиты? На самом деле ИДК. Я новичок в JS и хотел создать свой собственный стиль структуры.
Когда вы создаете модуль в JS на низком уровне во время компиляции, он будет обернут в IIFE, и использование IIFE внутри модулей не нужно. Если вы хотите провести событие для завершения других процессов, вам нужно использовать Async/Await или pormise.
Нет, нет необходимости в IIFE. Просто используйте асинхронное программирование



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Получил решение. Добавление функций ожидания в логический флаг работает.
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');
Как правило, лучший способ — отключить кнопку после нажатия и показать какой-нибудь счетчик, чтобы обеспечить визуальную обратную связь с пользователем.
Вообще говоря
async/await был представлен в ES2017 JavaScript и является синтаксическим сахаром для более старых промисов.async/awaitasync — это новый способ сказать return Promise((resolve) => { ... }).await является аналогом async и более новым способом сказать .then(result => { ... }).
await можно использовать только в функциях, помеченных как asynctry/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, я сразу понял? Синтаксический сахар обещания?
да. Это синтаксический сахар. Но имейте в виду, что некоторые старые браузеры поддерживают только промисы. А некоторые браузеры еще старше (и Internet Explorer) даже не поддерживают промисы. Обновил мой ответ этим объяснением @sniffingdoggo
Оооооооооооооооооооооооооооооооооооооооооооооооооооооооо уже наконец я понял на 100%. Спасибо за подробный ответ :-)
Нет проблем, рад, что смог помочь! Если у вас есть еще вопросы, не стесняйтесь спрашивать! @sniffingdoggo
Зачем вам нужно, чтобы класс был обернут в IIFE в модульной системе?