事件 - 对于可能发生多次的事情。
回调(或承诺)——针对可能发生一次的事情。
例如,当您因为需要从某个 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 的函数,则可以使用新的await
a 内的关键字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