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

2023-12-19

对于事件,发起者引发一个事件,该事件将由那些选择接收该事件的例程接收。接收方指定将从哪些发起方接收哪些事件。

通过回调,例程在完成后会通知调用者已完成。

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

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


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

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

例如,当您因为需要从某个 API 获取当前温度而调用一个函数时,该函数应该返回一个 Promise 或接受一个回调,稍后可以使用正确的值(或错误)调用该回调。

另一方面,如果您有一个调用的函数,因为您需要在每次变化时获取新的温度,那么该函数应该返回一个事件发射器(或采用事件处理程序附加到某个内部事件发射器) 。

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

首先,使用回调:

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

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

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));

它的工作原理是相同的,它以不同的风格编写,您可能会或可能不会发现更具可读性,但区别在于现在您不必在调用时附加回调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());
}

另一个区别是,如果您有一个返回 Promise 的函数,则可以使用新的awaita 内的关键字async function像这样:

async function x() {
    try {
        console.log('Data:', await a());
    } catch (err) {
       console.log('Error:', err);
    }
}

你不能使用await使用不返回承诺的函数。

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

To use async and await对于 Node v7.x,您需要使用--harmony标志,参见:

  • http://node.green/#async-functions http://node.green/#async-functions
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

了解何时使用事件以及何时使用回调 的相关文章

随机推荐