在通过导入/导出完成代码之前,如何防止发生事件?

时间:2019-07-15 12:27:44

标签: javascript node.js events import export

===================进度更新=================

我已经根据Mozillaanother教程制作了第一个异步函数。但是,它无法阻止事件,正如我预期的那样。当我在整个代码完成之前多次单击时,它会堆叠起来。

enter image description here

我的期望是使用异步并承诺禁用事件,直到整个代码完成为止,这是我使用像this CodePen example这样的回调的方式。

此外,我无法完全理解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.log('waiting . . .'))
                }, 2000)
            })
        }
    }
    result() {
        console.log('test');
        this.flag = true;
    }
    async group(e) {
        const a = await this.waiting();
        const b = await this.result();
    }
}
const async = new Async('.button');


===================原始问题==================

我正在Node js中使用import / export分离代码块,以便在重构时看起来更加清晰。

一个问题是当我将布尔值标志作为参数传递给this.flag时,名为init.js的布尔标志不能防止事件覆盖:

enter image description here

先查看代码:

// =================== 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.log('waiting . . .');
            setTimeout(bound, 1000, flag);
        }
        done(flag) {
            console.log('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.log(`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.log('waiting . . .');
    setTimeout(bound, 1000);
}
done(flag) {
    console.log('done');
    this.flag = true;
}

我想知道为什么该标志传递给另一个js file时为什么不能阻止该事件,以及如何使其暂时禁用该事件。

2 个答案:

答案 0 :(得分:5)

说明

一般来说

  • async/await模式是在JavaScript ES2017中引入的,它是较旧的Promise的语法糖
  • 某些较旧的浏览器不支持async/await
  • asyncreturn Promise((resolve) => { ... })的更新说法。
  • awaitasync的对应词,是更新的.then(result => { ... })称呼方式。
    • await仅可用于标记为async的函数中
  • try/catch.catch(error => { ... })的对应物。它实际上不是新的,但是您可以在这种情况下使用它。

您可以了解有关async/await here

的更多信息

代码

我对您的代码进行了一些较小的更改,以使其更有意义并编写了一些注释,以便您了解此处发生的一切。

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.log('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.log)
                }, 2000)
            } else {
                reject('There is already a button function running'); // <-- reject is like throwing an error
            }
        })
    }
    result() {
        console.log('test');
    }
    async group(e) {
        try {
            const a = await this.waiting(); // <-- Assigns 'Done' to the variable a
            console.log(a); // <-- prints the message

            this.result(); // <-- prints 'test' immidiatly after the above console.log
        } catch (error) {
            console.log(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.log(result); // Will print "Done" after 2000 milliseconds

            this.result(); // Will print test instantly after the above console.log(). You dont need to await it, because it is not an async function
        }).catch(error => {
            console.log(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.log('Waiting ... '); 
                
                setTimeout(() => { 
                    this.isRunning = false;
                    resolve('Done');
                }, 2000)
            } else {
                reject('There is already a button function running'); 
            }
        })
    }
    result() {
        console.log('test');
    }
    async group(e) {
        try {
          const a = await this.waiting(); 
          console.log(a); 
          this.result();
        } catch(error) {
          console.log(error);
        }
    }
}
const asyncButton = new Async('.button');
<button class="button">Test</button>

答案 1 :(得分:0)

有解决方案。将await函数添加到boolean标志中是可行的。

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.log('waiting . . .'))
            }, 1000)
        })
    }
    result() {
        console.log('test');
        this.flag = true;
    }
    async group(e) {
        // console.log(this.flag);
        if (this.flag) {
            this.flag = false;
            console.log('test');
            const a = await this.waiting();
            const b = await this.result();
        }

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