javascript 等待异步函数完成而不添加回调
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18150531/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Wait for asynchronous function to finish without adding callback
提问by gr3co
I'm writing tests for my Node.js/Express/Mongoose project using Mocha and Should.js, and I'm testing out my functions that access my MongoDB. I'm want these tests to be completely independent from the actual records in my database, so I want to create an entry and then load it, and do all my tests on it, then delete it. I have my actual functions written (I'm writing tests after the entire project is complete) such that the create
function does not have a callback; it simply just renders a page when it's done. In my tests script, I call my load_entry
function after I call create
, but sometimes create
takes longer than usual and thus load_entry
throws an error when it cannot actually load the article since it has yet to be created. Is there any way to make sure an asynchronous function is finished without using callbacks?
我正在使用 Mocha 和 Should.js 为我的 Node.js/Express/Mongoose 项目编写测试,我正在测试访问我的 MongoDB 的函数。我希望这些测试完全独立于我的数据库中的实际记录,所以我想创建一个条目然后加载它,并对其进行所有测试,然后将其删除。我编写了我的实际函数(我在整个项目完成后编写测试),这样create
函数就没有回调;它只是在完成后呈现一个页面。在我的测试脚本中,我在调用load_entry
后调用我的函数create
,但有时create
比平时花费的时间更长,因此load_entry
当它无法实际加载文章时抛出错误,因为它尚未创建。有没有办法确保异步函数在不使用回调的情况下完成?
Please let me know if there is any more info I can provide. I looked all over Google and couldn't find anything that really answered my question, since most solutions just say "use a callback!"
如果我能提供更多信息,请告诉我。我在谷歌上找遍了,找不到任何能真正回答我的问题的东西,因为大多数解决方案只是说“使用回调!”
回答by Eric Hotinger
Use what is known as a promise
使用所谓的 promise
You can read more about it here.
您可以在此处阅读更多相关信息。
There are lots of great libraries that can do this for you.
有很多很棒的库可以为您做到这一点。
Q.jsis one I personally like and it's widely used nowadays. Promises also exist in jQueryamong many others.
Q.js是我个人喜欢的一种,现在被广泛使用。Promise 也存在于jQuery中。
Here's an example of using a q promise with an asynchronous json-p
call: DEMO
这是将 aq promise 与异步json-p
调用一起使用的示例:DEMO
var time;
$.ajax({
dataType: 'jsonp',
type: 'GET',
url: "http://www.timeapi.org/utc/now.json",
success: function (data) {
time = data;
},
error: function (data) {
console.log("failed");
}
})
.then(function(){ // use a promise library to make sure we synchronize off the jsonp
console.log(time);
});
回答by lmjohns3
This is definitely the kind of thing you want a callback for. Barring that, you're going to have to write some kind of callback wrapper that polls the database to determine when it has finished creating the relevant records, and then emits an event or does some other async thing to allow the test to continue.
这绝对是您想要回调的那种事情。除此之外,您将不得不编写某种回调包装器来轮询数据库以确定它何时完成了相关记录的创建,然后发出事件或执行其他一些异步操作以允许测试继续。
回答by Halcyon
Since the only native way to do asynchronous things are: setTimeout
, setInterval
and addEventListener
, and they all take a callback you will eventually have to use a callback somewhere.
由于执行异步操作的唯一本机方式是:setTimeout
、setInterval
和addEventListener
,并且它们都采用回调,因此您最终将不得不在某处使用回调。
However, you can hide that by using Promises/A, also known as Deferreds.
但是,您可以使用 Promises/A(也称为 Deferreds)来隐藏它。
Your code could look like this:
您的代码可能如下所示:
db.create_entry("foo", data).done(function (entry) {
db.delete_entry(entry).done(function () {
console.log("entry is deleted");
});
});
Using then-chaining:
使用 then-chaining:
db.create_entry("foo", data).then(function (entry) {
return db.delete_entry(entry);
}).done(function () {
console.log("entry is deleted");
});;
回答by gr3co
I found a solution that works. What I did was to add a callback to my function (next
) and only call it if it's specified (i.e., for the tests):
我找到了一个有效的解决方案。我所做的是向我的函数 ( next
)添加一个回调,并且仅在指定时才调用它(即,用于测试):
//more stuff above
article.save(function(err){
if (!err) {
console.log(req.user.username + ' wrote ' + article.slug)
return next() || res.redirect('/admin')
}
return next(err) || res.render('articles/entry_form', {
title: 'New Entry',
article: article,
})
})
This way, when I run the actual server and no callback is specified, it won't throw an error, because it will simply return the res.render
statement.
这样,当我运行实际服务器并且没有指定回调时,它不会抛出错误,因为它只会返回res.render
语句。