了解何时使用事件以及何时使用回调

时间:2017-02-14 17:02:43

标签: javascript node.js

对于事件,启动器会引发一个事件,该事件将由已选择接收该事件的那些例程接收。接收器指定它将从哪些启动器接收的事件。

使用回调,完成后的例程会通知调用者完成。

所以我很困惑我应该在哪里使用事件或者我应该在哪里使用回调,因为我可以完成回调对事件的处理,但会导致在应用程序中创建大量事件。

在编码,使用事件或回调时应该遵循什么样的好方法?

1 个答案:

答案 0 :(得分:2)

事件 - 对于可能发生多次的事情。

回调(或承诺) - 对于可能发生一次的事情。

例如,当你有一个函数被调用因为你需要从某个API获取当前温度时,该函数应该返回一个promise或者一个回调,以后可以使用正确的值(或错误)调用

另一方面,如果你有一个你调用的函数,因为你每次更改时都需要获得一个新的温度,那么这个函数应该返回一个事件发射器(或者把一个事件处理程序附加到一些内部事件发射器)。

现在,关于何时使用回调以及何时使用promises的问题有点棘手,因为它们适用于相同类型的情况 - 当您想知道某些异步操作的结果时(某些数据或错误) )。由于两者都适用于相同的情况,因此请考虑两个读取文件内容的示例。

首先,回调:

let fs = require('fs');
fs.readFile('a.txt', 'utf-8', (err, data) => {
    if (err) {
        console.log('Error:', err.message);
    } else {
        console.log('Data:', data.trim());
    }
});

如果没有文件,则会打印出来:

Error: ENOENT: no such file or directory, open 'a.txt'

如果有文件,则会打印:

Data: Contents of a.txt

现在,与承诺相同:

let fs = require('mz/fs');
fs.readFile('b.txt', 'utf-8')
    .then(data => {
        console.log('Data:', data.trim());
    })
    .catch(err => {
        console.log('Error:', err.message);
    });

它与前一个示例完全相同。

对于这个简单的例子,差异可能不是很明显,但如果你想要一个能够抽象出某些逻辑的函数会怎样呢。

例如,使用回调:

let fs = require('fs');
function a(cb) {
    fs.readFile('b.txt', 'utf-8', (err, data) => {
        if (err) {
            return cb('a() error: ' + err.message);
        }
        cb(null, 'a() data: ' + data.trim());
    });
}
a((err, data) => {
    if (err) {
        console.log('Error:', err);
    } else {
        console.log('Data:', data);
    }
});

它将打印此

Error: a() error: ENOENT: no such file or directory, open 'a.txt'

或类似的东西:

Data: a() data: Contents of a.txt

现在,与promises的不同之处在于,您可以将它存储在变量中,从函数返回它,或者在附加成功/错误处理程序之前将其作为参数传递给其他函数。例如:

let fs = require('mz/fs');
function a() {
    return fs.readFile('a.txt', 'utf-8')
        .then(data => 'a() data: ' + data.trim())
        .catch(err => Promise.reject('a() error: ' + err.message));
}
let promise = a();
promise.then(data => console.log('Data:', data))
       .catch(err => console.log('Error:', err));

它的工作方式相同,它以不同的风格编写,您可能会或可能不会更具可读性,但不同的是,现在您不必在调用{{时附加回调1}}功能。你可以在其他地方做到。

如果你不想改变错误信息,那就是回调:

a()

这有承诺:

function a(cb) {
    fs.readFile('a.txt', 'utf-8', (err, data) => {
        if (err) {
            return cb(err);
        }
        cb(null, 'a() data: ' + data.trim());
    });

另一个区别是,如果您有一个返回承诺的函数,您可以在function a() { return fs.readFile('a.txt', 'utf-8') .then(data => 'a() data: ' + data.trim()); } 内使用新的await关键字,如下所示:

async function

您不能将async function x() { try { console.log('Data:', await a()); } catch (err) { console.log('Error:', err); } } 与不返回承诺的函数一起使用。

例如,当您需要读取文件await以获取其中包含的另一个文件名,然后在更复杂的情况下处理所有错误时读取其他文件并打印其内容时,它会变得非常方便。

要在Node v7.x中使用a.txtasync,您需要使用await标记,请参阅: