如何为 Node.js 编写异步函数

我曾试图研究如何准确地编写异步函数。在翻阅了大量文档之后,我仍然不清楚。

如何为 Node 编写异步函数? 如何正确实现错误事件处理?

另一种问我问题的方式是: 我应该如何解释以下函数?

var async_function = function(val, callback){
process.nextTick(function(){
callback(val);
});
};

此外,我还找到了 这个问题在 SO 上(“如何在 node.js 中创建非阻塞异步函数?”)有意思。我觉得还没有答案。

109568 次浏览

You seem to be confusing asynchronous IO with asynchronous functions. node.js uses asynchronous non-blocking IO because non blocking IO is better. The best way to understand it is to go watch some videos by ryan dahl.

如何为 Node 编写异步函数?

只需编写普通函数,唯一的区别是它们不会立即执行,而是作为回调函数传递。

我应该如何正确地实现错误事件处理

Generally API's give you a callback with an err as the first argument. For example

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到控制台。特别是当前的 eventloop 调用栈为空时,process.nextTick会触发。在 async_functionconsole.log(43)运行之后,该调用堆栈为空。所以我们先打印43然后是42。

您可能需要阅读一下事件循环。

你应该看看这个: NodeTuts 第19集-异步迭代模式

它应该能回答你的问题。

试试这个,它既适用于节点,也适用于浏览器。

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

仅仅通过复试是不够的。 例如,必须使用 settimer 才能使函数异步。

Examples: 非异步函数:

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

如果你将运行上面的例子,这应该是好的,将不得不等待,直到这些函数将完成工作。

Pseudo multithread (async) functions:

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

这将是真正的异步。 这应该是好的,将在异步完成之前写入。

如果你知道一个函数返回一个承诺,我建议在 JavaScript 中使用新的异步/等待特性。它使语法看起来是同步的,但工作是异步的。当您向函数添加 async关键字时,它允许您在该范围内做出 await承诺:

async function ace() {
var r = await new Promise((resolve, reject) => {
resolve(true)
});


console.log(r); // true
}

如果一个函数没有返回一个承诺,我建议将它包装在您定义的新承诺中,然后解析您想要的数据:

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: ... }
}

底线: 利用承诺的力量。

我花了太多的时间在 node.js 上,我主要负责前端。

我发现这一点非常重要,因为所有的节点方法都异步处理回调,并将其转换为  诺言更好地处理它。

我只是想展示一个可能的结果,更简洁易读。使用带有异步的 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)适用于 回复(读取事件打印循环)场景, 使用未定义的也工作。