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


114

我试图研究应如何精确地编写异步函数。经过大量的文档研究后,我仍然不清楚。

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

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

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

另外,我在SO上发现了这个问题(“如何在node.js中创建非阻塞异步函数?”)。我感觉还没有得到答复。


14
这就是为什么我问。对我来说,这些功能有何不同是不明显的。
2011年

我建议你看看setTimeoutsetInterval你喜欢的浏览器和玩他们。或ajax回调(可能是最接近节点体验的事件),或事件监听器,用于您熟悉的事件(例如单击和加载事件)。异步模型已经存在于浏览器中,并且它们在节点中完全相同。
戴文,2011年

@davin-猜猜我那时还不完全理解异步模型。
2011年

@Kriem,昨天我回答了一些可能会有所帮助的内容:stackoverflow.com/questions/6883648 / ...这不是对您问题的答案,但这是很主题的。尝试阅读问题并在那里回答,并尝试使用代码来尝试理解正在发生的事情。
戴文,2011年

2
@Raynos“异步功能”的定义是什么?
安德森·格林

Answers:


85

您似乎将异步IO与异步功能混淆了。由于非阻塞IO更好,所以node.js使用异步非阻塞IO。理解它的最好方法是去观看ryan dahl的一些视频。

如何为Node编写异步函数?

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

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

通常,API会为您提供以err作为第一个参数的回调。例如

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调用栈为空之后触发。这调用堆栈是空后async_functionconsole.log(43)已经运行。因此,我们先打印43,再打印42。

您可能应该对事件循环进行一些阅读。


我看过达尔影片,但是我似乎对这件事不了解。:(
Kriem

1
@Kriem查看最新答案并了解事件循环
Raynos 2011年

1
感谢堡垒的见解。我现在更加了解自己所缺乏的知识。:)您的最后一个例子对您有所帮助。
2011年

我认为您对异步IO的陈述“更好”是太笼统的说法。从这个意义上讲,是的,但总的来说并非如此。
杰克B

在第一个代码示例中,您检查了err参数,但此后没有返回。如果发生错误,该代码将继续运行,并可能在您的应用程序中引起严重的问题。
加布里埃尔·麦卡丹斯

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

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



3

如果您知道某个函数返回一个Promise,我建议在JavaScript中使用新的async / await功能。它使语法看起来是同步的,但异步地工作。当您将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: ... }
}

底线:利用承诺的力量。


这里要记住的是,承诺主体仍是同步执行的。
shadow0359 '19

2

试试这个,它对节点和浏览器都有效。

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

18
4下注,甚至没有一项建设性评论。:\
Omer

6
@Omer这就是SO的生命。
Piece Digital

6
@NorbertoBezi也许代码对您来说是自我解释,但对于发布答案的人却不是。这就是为什么在投票时进行解释总是一个好习惯。
2016年

0

我在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(读取事件打印循环)方案中,使用也未定义工作。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.