我试图研究应该如何编写完全异步的函数。经过大量的文档研究后,我仍然不清楚。
如何为Node编写异步函数?我该如何正确实现错误事件处理?
提出问题的另一种方法是:我应该如何解释以下功能?
var async_function = function(val, callback){
process.nextTick(function(){
callback(val);
});
};
另外,我发现 this question on SO (“如何在node.js中创建非阻塞异步函数?”)很有趣。我觉得它还没有得到回答。
答案 0 :(得分:84)
您似乎将异步IO与异步功能混淆。 node.js使用异步非阻塞IO,因为非阻塞IO更好。理解它的最好方法是观看ryan dahl的一些视频。
如何为Node编写异步函数?
只需编写普通函数,唯一的区别是它们不会立即执行,而是作为回调传递。
我应该如何正确实施错误事件处理
通常API会给你一个带有错误作为第一个参数的回调。例如
database.query('something', function(err, result) {
if (err) handle(err);
doSomething(result);
});
是一种常见的模式。
另一种常见模式是on('error')
。例如
process.on('uncaughtException', function (err) {
console.log('Caught exception: ' + err);
});
修改强>
var async_function = function(val, callback){
process.nextTick(function(){
callback(val);
});
};
上述函数称为
async_function(42, function(val) {
console.log(val)
});
console.log(43);
将异步打印42
到控制台。特别是process.nextTick
在当前eventloop callstack为空后触发。 async_function
和console.log(43)
运行后,该调用堆栈为空。所以我们打印43,然后是42。
你应该对事件循环做一些阅读。
答案 1 :(得分:9)
仅通过回调是不够的。 例如,您必须使用settimer来使函数异步。
实施例: 不是异步函数:
function a() {
var a = 0;
for(i=0; i<10000000; i++) {
a++;
};
b();
};
function b() {
var a = 0;
for(i=0; i<10000000; i++) {
a++;
};
c();
};
function c() {
for(i=0; i<10000000; i++) {
};
console.log("async finished!");
};
a();
console.log("This should be good");
如果您将运行以上示例,这应该是好的,将不得不等待,直到这些功能将完成工作。
伪多线程(异步)函数:
function a() {
setTimeout ( function() {
var a = 0;
for(i=0; i<10000000; i++) {
a++;
};
b();
}, 0);
};
function b() {
setTimeout ( function() {
var a = 0;
for(i=0; i<10000000; i++) {
a++;
};
c();
}, 0);
};
function c() {
setTimeout ( function() {
for(i=0; i<10000000; i++) {
};
console.log("async finished!");
}, 0);
};
a();
console.log("This should be good");
这个将是异常的异步。 在异步完成之前,这应该是好的。
答案 2 :(得分:5)
你应该看一下:Node Tuts episode 19 - Asynchronous Iteration Patterns
它应该回答你的问题。
答案 3 :(得分:3)
试试这个,它适用于节点和浏览器。
isNode = (typeof exports !== 'undefined') &&
(typeof module !== 'undefined') &&
(typeof module.exports !== 'undefined') &&
(typeof navigator === 'undefined' || typeof navigator.appName === 'undefined') ? true : false,
asyncIt = (isNode ? function (func) {
process.nextTick(function () {
func();
});
} : function (func) {
setTimeout(func, 5);
});
答案 4 :(得分:3)
如果您知道函数返回一个promise,我建议在JavaScript中使用新的async / await功能。它使语法看起来是同步的,但是异步工作。将async
关键字添加到函数后,它允许您在该范围内await
个承诺:
async function ace() {
var r = await new Promise((resolve, reject) => {
resolve(true)
});
console.log(r); // true
}
如果某个函数没有返回一个promise,我建议将它包装在你定义的新promise中,然后解析你想要的数据:
function ajax_call(url, method) {
return new Promise((resolve, reject) => {
fetch(url, { method })
.then(resp => resp.json())
.then(json => { resolve(json); })
});
}
async function your_function() {
var json = await ajax_call('www.api-example.com/some_data', 'GET');
console.log(json); // { status: 200, data: ... }
}
底线:利用Promises的力量。
答案 5 :(得分:1)
在node.js中,我花了太多时间来完成这样的任务。我主要是前端人员。
我发现这很重要,因为所有节点方法都异步处理回调,并将其转换为Promise更好地处理它。
我只是想展示一个可能的结果,更加简洁和可读。将ECMA-6与异步功能配合使用,您可以这样编写。
async function getNameFiles (dirname) {
return new Promise((resolve, reject) => {
fs.readdir(dirname, (err, filenames) => {
err !== (undefined || null) ? reject(err) : resolve(filenames)
})
})
}
(undefined || null)
适用于 repl (读取事件打印循环)方案,
使用undefined也可以。