我正在使用一个名为bootbox
的jQuery库
bootbox.dialog({
title: "Group",
buttons: {
success: {
label: "OK",
className: "btn-success",
callback: function () {
postForm();
}
}
}
});
function postForm() {
$.ajax({
type: "POST",
url: $("#add-group").val(),
data: $("#form").serialize(),
success: function (data) {
return true;
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
return false;
}
});
}
当我点击“确定”按钮时,除非我返回如下的假值:
callback: function () {
return false;
}
对话框将关闭。
在回调函数中,我正在调用postForm
,这是一个向我的服务器端进行AJAX调用以执行某些操作的函数。根据该操作的结果,我想保持对话框仍然打开。
但是因为它是一个AJAX调用,并且结果需要一段时间才能返回,所以无论我的结果如何,对话框都会在postForm()
之后立即关闭。
如何告诉javascript等待ajax调用的结果?
如果我能做到这样的话会很棒:
callback: function () {
var result = await postForm();
return result;
}
我认为Promises正是你所要求的。
.promise()
返回一个Promise对象,以观察绑定到已排队或未排队的特定类型的所有操作何时完成。例如
var div = $( "<div>" );
div.promise().done(function( arg1 ) {
// Will fire right away and alert "true"
alert( this === div && arg1 === div );
});
欲了解更多信息,请参阅:https://api.jquery.com/promise/
延迟承诺更接近异步行为:
deferred.promise()
deferred.promise()方法允许异步函数阻止其他代码干扰其内部请求的进度或状态。 Promise只暴露附加其他处理程序或确定状态所需的延迟方法(then
,done
,fail
,always
,pipe
,progress
和state
),但不会暴露那些改变状态的方法(resolve
,reject
,notify
,resolveWith
,rejectWith
)和notifyWith
)。
如果提供了target,deferred.promise()
会将方法附加到它上,然后返回此对象而不是创建一个新对象。这可以用于将Promise行为附加到已存在的对象。
如果要创建Deferred,请保留对Deferred的引用,以便在某些时候可以解析或拒绝它。通过deferred.promise()
仅返回Promise对象,以便其他代码可以注册回调或检查当前状态。
例:
function asyncEvent() {
var dfd = new jQuery.Deferred();
// Resolve after a random interval
setTimeout(function() {
dfd.resolve( "hurray" );
}, Math.floor( 400 + Math.random() * 2000 ) );
// Reject after a random interval
setTimeout(function() {
dfd.reject( "sorry" );
}, Math.floor( 400 + Math.random() * 2000 ) );
// Show a "working..." message every half-second
setTimeout(function working() {
if ( dfd.state() === "pending" ) {
dfd.notify( "working... " );
setTimeout( working, 500 );
}
}, 1 );
// Return the Promise so caller can't change the Deferred
return dfd.promise();
}
// Attach a done, fail, and progress handler for the asyncEvent
$.when( asyncEvent() ).then(
function( status ) {
alert( status + ", things are going well" );
},
function( status ) {
alert( status + ", you fail this time" );
},
function( status ) {
$( "body" ).append( status );
}
);
有关更多信息,请参阅Deferred对象的文档:http://api.jquery.com/category/deferred-object/
jQuery.when()
提供一种基于一个或多个对象执行回调函数的方法,通常是表示异步事件的Deferred对象。示例:
$.when( $.ajax( "test.aspx" ) ).then(function( data, textStatus, jqXHR ) {
alert( jqXHR.status ); // Alerts 200
});
JavaScript(目前)没有相当于async
/ await
的语言。有适用于JavaScript的various promise libraries,可以为您提供Task
类型的粗略等效。这是原始回调之上的一个很好的步骤,但除了最简单的场景之外,你最终还是会遇到笨拙的嵌套或回调意大利面。
JavaScript ECMAScript 6(“和谐”)预计将包括generators。 ES6有望在今年晚些时候正式上市,但可能需要一段时间才能安全地假设用户的浏览器支持发电机。
通过combining generators with promises,你可以获得真正的async
/ await
等价物。
你不能。在JS中没有相当于await
的东西。
您必须通过在调用postForm
时返回false来模拟它,然后在从AJAX调用执行回调函数时关闭对话框。
编辑/更新:从ES2017开始有async / await支持 - 虽然我不知道它是否与jQuery一起使用。
随着ES2017的出现,这个问题的答案是async / await。 这是“回调地狱”的JS解决方案。 Promise相当于System.Threading.Tasks.Task。您可以在异步函数中等待Promise。 与C#不同,无法在同步函数中调用异步函数。 因此,您可以在异步函数中等待Promise,并且只能在异步函数中等待。
async function foo()
{
return 123;
}
let result = await foo();
console.log(result)
您可以使用TypeScript或babel将async / await转换回ES5(当IE11存在时)。 IE11有一个承诺polyfill。 有关详细信息,请参阅ECMA-draft 262或MDN。
一个很好的例子是FETCH api。 fetch-API适用于异步/等待ajax请求。 为什么?因为如果你必须宣传XmlHttpRequest,它看起来像这样:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta http-equiv="cache-control" content="max-age=0" />
<meta http-equiv="cache-control" content="no-cache" />
<meta http-equiv="expires" content="0" />
<meta http-equiv="expires" content="Tue, 01 Jan 1980 1:00:00 GMT" />
<meta http-equiv="pragma" content="no-cache" />
<meta charset="utf-8" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="Content-Language" content="en" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<meta name="google" value="notranslate" />
<!--
<meta name="author" content="name" />
<meta name="description" content="description here" />
<meta name="keywords" content="keywords,here" />
<link rel="shortcut icon" href="favicon.ico" type="image/vnd.microsoft.icon" />
<link rel="stylesheet" href="stylesheet.css" type="text/css" />
-->
<title>Title</title>
<style type="text/css" media="all">
body
{
background-color: #0c70b4;
color: #546775;
font: normal 400 18px "PT Sans", sans-serif;
-webkit-font-smoothing: antialiased;
}
</style>
<script type="text/javascript">
<!--
// http://localhost:57566/foobar/ajax/json.ashx
var ajax = {};
ajax.x = function () {
if (typeof XMLHttpRequest !== 'undefined') {
return new XMLHttpRequest();
}
var versions = [
"MSXML2.XmlHttp.6.0",
"MSXML2.XmlHttp.5.0",
"MSXML2.XmlHttp.4.0",
"MSXML2.XmlHttp.3.0",
"MSXML2.XmlHttp.2.0",
"Microsoft.XmlHttp"
];
var xhr;
for (var i = 0; i < versions.length; i++) {
try {
xhr = new ActiveXObject(versions[i]);
break;
} catch (e) {
}
}
return xhr;
};
ajax.send = function (url, callback, method, data, async) {
if (async === undefined)
{
async = true;
}
var x = ajax.x();
x.open(method, url, async);
x.onreadystatechange = function () {
if (x.readyState == 4) {
callback(x.responseText)
}
};
if (method == 'POST') {
x.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
}
x.send(data)
};
ajax.get = function (url, data, callback, async) {
var query = [];
for (var key in data) {
query.push(encodeURIComponent(key) + '=' + encodeURIComponent(data[key]));
}
ajax.send(url + (query.length ? '?' + query.join('&') : ''), callback, 'GET', null, async)
};
ajax.post = function (url, data, callback, async) {
var query = [];
for (var key in data) {
query.push(encodeURIComponent(key) + '=' + encodeURIComponent(data[key]));
}
ajax.send(url, callback, 'POST', query.join('&'), async)
};
///////////
function testAjaxCall() {
ajax.get("./ajax/json.ashx", null, function (bError, strMessage, iStatus)
{
console.log("args:", arguments);
console.log("Error:", bError);
console.log("Message:", strMessage);
console.log("Status:", iStatus);
}
, true
);
}
-->
</script>
</head>
<body>
<script type="text/javascript">
function ajaxGet(url, data)
{
var result;
return new Promise(function (resolve, reject)
{
ajax.get(url, data, function (bError, strMessage, iStatus)
{
// console.log("args:", arguments);
// console.log("Error:", bError);
// console.log("Message:", strMessage);
// console.log("Status:", iStatus);
result = bError;
resolve(result);
}
,true
);
}
);
}
async function main()
{
var ajaxResult = await ajaxGet("./ajax/json.ashx");
console.log("ajaxResult: ", ajaxResult);
}
async function lol()
{
var res = null;
var myPromise = new Promise(function (resolve, reject)
{
// Standard AJAX request setup and load.
var request = new XMLHttpRequest();
// Request a user's comment from our fake blog.
request.open('GET', 'https://localhost:57566/ajax/json.ashx');
/*
// Set function to call when resource is loaded.
// Onload same as onreadystatechange - onload added with XHR2
request.onload = function ()
{
// internal server error/404
if (request.status === 200)
{
res = request.response;
// console.log(request.response);
console.log("onload- resolving promise");
resolve(request.response);
} else
{
console.log("onload- rejectinv promise");
reject('Page loaded, but status not OK.');
}
};
*/
request.onreadystatechange = function ()
{
console.log("readystate:", request.readyState);
console.log("status:", request.status)
if (request.readyState != 4) return;
// XMLHttpRequest.DONE = 200, 0=cancelled 304 = redirect
//if (!(request.status != 200 && request.status != 304 && request.status != 0))
if (request.status === 200)
{
console.log("successy")
resolve(request.responseText); // Success
return;
}
if (request.status != 200 && request.status != 0 && request.status != 304)
{
console.log('HTTP error ' + request.status);
// reject('Page loaded, but status not OK.');
reject(new Error("Server error - Status NOK", "filename", "linenum666")); // Error
return;
}
if (request.status === 0)
{
console.log("cancelled:", request)
//resolve(null); // Cancelled, HTTPS protocol error
return;
}
reject(new Error("Strange error", "filename", "linenum666")); // Some Error
};
// Set function to call when loading fails.
request.onerror = function ()
{
// Cannot connect
console.log("OMG OnError");
// reject('Aww, didn\'t work at all. Network connectivity issue.');
reject(new Error("Aww, didn\'t work at all. Network connectivity issue.", "filename", "linenum666")); // Some Error
};
if (!navigator.onLine)
{
console.log("No internet connection");
reject("No internet connection");
}
else
{
try
{
request.send();
}
catch (ex)
{
console.log("send", ex.message, ex);
}
}
});
return myPromise;
}
async function autorun()
{
console.clear();
// await main();
try
{
var resp = await lol();
console.log("resp:", resp);
}
catch (ex)
{
console.log("foo", ex.message, ex);
}
console.log("I am here !");
}
if (document.addEventListener) document.addEventListener("DOMContentLoaded", autorun, false);
else if (document.attachEvent) document.attachEvent("onreadystatechange", autorun);
else window.onload = autorun;
</script>
</body>
</html>
你可以使用ES6生成器和yield
功能与Google Traceur Compiler,正如我所描述的here。
来自Traceur团队的some feedback表明它是生产质量的工具。它还有experimental support用于async/await
。
请参阅Stefan's answer,了解如何使用ES2015 async / await。
原始答案
您可以考虑asyncawait,它可以有效地让您编写如下代码
var foo = async (function() {
var resultA = await (firstAsyncCall());
var resultB = await (secondAsyncCallUsing(resultA));
var resultC = await (thirdAsyncCallUsing(resultB));
return doSomethingWith(resultC);
});
而不是以下
function foo2(callback) {
firstAsyncCall(function (err, resultA) {
if (err) { callback(err); return; }
secondAsyncCallUsing(resultA, function (err, resultB) {
if (err) { callback(err); return; }
thirdAsyncCallUsing(resultB, function (err, resultC) {
if (err) {
callback(err);
} else {
callback(null, doSomethingWith(resultC));
}
});
});
});
}
虽然这并没有回答“在JavaScript中等待C#等同于什么?”问题,问题中的代码可以很容易地工作。 bootbox.dialog
函数返回一个对象,因此您可以调整显示的代码,如下所示:
var dialog = bootbox.dialog({
title: "Group",
buttons: {
success: {
label: "OK",
className: "btn-success",
callback: function () {
postForm();
return false; // add this return here
}
}
}
});
然后将ajax调用调整为:
function postForm() {
$.ajax({
type: "POST",
url: $("#add-group").val(),
data: $("#form").serialize(),
success: function (data) {
// add this call to the underlying Bootstrap modal object
dialog.modal('hide');
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
// Maybe inject an error message into the dialog?
}
});
}