javascript/jquery 中 C# 的 await 等价物是什么?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/23263429/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 00:39:15  来源:igfitidea点击:

What's C#'s await equivalent in javascript/jquery?

javascriptasync-awaitbootbox

提问by Null Reference

I'm using a jQuery library called bootbox

我正在使用一个名为的 jQuery 库 bootbox

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

When I click on the "OK" button, unless I return a false value like this:

当我单击“确定”按钮时,除非我返回这样的错误值:

callback: function () {
    return false;
}

the dialog will close.

对话框将关闭。

In the callback function, I'm calling postFormwhich is a function that makes an AJAX call to my server side to perform some operation. Depending on the outcome of that operation, I would like to keep the dialog still open.

在回调函数中,我调用postForm了一个函数,它向我的服务器端进行 AJAX 调用以执行一些操作。根据该操作的结果,我希望对话框保持打开状态。

But because it's an AJAX call, and the result takes a while to come back, the dialog closes immediately after postForm()regardless of my result.

但是因为它是一个 AJAX 调用,并且结果需要一段时间才能返回,所以postForm()无论我的结果如何,对话框都会立即关闭。

How can I tell javascript to await for the result of the ajax call?

如何告诉 javascript 等待 ajax 调用的结果?

It'll be great if I can do something like this:

如果我能做这样的事情,那就太好了:

callback: function () {
    var result = await postForm();
    return result;
}

采纳答案by Pranav Singh

I think Promisesis exactly what you are asking.

我认为Promises正是你要问的。

.promise()

.promise()

Return a Promise object to observe when all actions of a certain type bound to the collection, queued or not, have finished. e.g.

返回一个 Promise 对象以观察绑定到集合的特定类型的所有操作(无论是否排队)何时完成。例如

var div = $( "<div>" );

div.promise().done(function( arg1 ) {
  // Will fire right away and alert "true"
  alert( this === div && arg1 === div );
});

For more info refer : https://api.jquery.com/promise/

有关更多信息,请参阅:https: //api.jquery.com/promise/

Deferred Promise is closer to async behaviour:

延迟承诺更接近异步行为

deferred.promise()

deferred.promise()

The deferred.promise() method allows an asynchronous function to prevent other code from interfering with the progress or status of its internal request. The Promise exposes only the Deferred methods needed to attach additional handlers or determine the state (then, done, fail, always, pipe, progress, and state), but not ones that change the state (resolve, reject, notify, resolveWith, rejectWith, and notifyWith).

deferred.promise() 方法允许异步函数防止其他代码干扰其内部请求的进度或状态。无极公开只有附加其他处理或确定状态所需的递延方法(thendonefailalwayspipeprogress,和state),而不是那些改变状态(resolverejectnotifyresolveWithrejectWith,和notifyWith)。

If target is provided, deferred.promise()will attach the methods onto it and then return this object rather than create a new one. This can be useful to attach the Promise behavior to an object that already exists.

如果提供了目标,deferred.promise()则将方法附加到其上,然后返回此对象而不是创建一个新对象。这对于将 Promise 行为附加到已经存在的对象很有用。

If you are creating a Deferred, keep a reference to the Deferred so that it can be resolved or rejected at some point. Return only the Promise object via deferred.promise()so other code can register callbacks or inspect the current state.

如果您正在创建一个 Deferred,请保留对 Deferred 的引用,以便在某个时候可以解决或拒绝它。仅返回 Promise 对象 viadeferred.promise()以便其他代码可以注册回调或检查当前状态。

Example:

例子:

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

For more information, see the documentation for Deferred object: http://api.jquery.com/category/deferred-object/

有关更多信息,请参阅延迟对象的文档:http: //api.jquery.com/category/deferred-object/

jQuery.when()

jQuery.when()

Provides a way to execute callback functions based on one or more objects, usually Deferred objects that represent asynchronous events.Example:

提供一种基于一个或多个对象执行回调函数的方法,通常是表示异步事件的延迟对象。示例:

$.when( $.ajax( "test.aspx" ) ).then(function( data, textStatus, jqXHR ) {
  alert( jqXHR.status ); // Alerts 200
});

回答by Stephen Cleary

JavaScript does not (currently) have a language equivalent of async/await. There are various promise librariesavailable for JavaScript that give you a rough equivalent of the Tasktype. This is a good step above raw callbacks, but you still end up with awkward nesting or callback spaghetti in all but the simplest scenarios.

JavaScript(当前)没有与async/等效的语言await。有多种可用于 JavaScript 的Promise 库,它们为您提供了该Task类型的粗略等效项。这是原始回调之上的一个很好的步骤,但除了最简单的场景之外,您仍然会遇到尴尬的嵌套或回调意大利面。

JavaScript ECMAScript 6 ("Harmony") is expected to include generators. ES6 is on track to become official later this year, but it will probably be some time after that before you can safely assume that your users' browsers support generators.

JavaScript ECMAScript 6(“Harmony”)预计将包含generators。ES6 有望在今年晚些时候成为正式版本,但在那之后您可能需要一段时间才能安全地假设您的用户的浏览器支持生成器。

By combining generators with promises, you can achieve a true async/awaitequivalent.

通过将 generators 与 promises 相结合,您可以实现真正的async/await等效的。

回答by Stefan Steiger

With the advent of ES2017, the answer to this question is async/await.
It's THE JS solution for “callback hell”. Promise is the equivalent to System.Threading.Tasks.Task. You can await a Promise in an async function.
Unlike in C#, there is no way to call an async-function in a synchronous function.
So you can awaita Promise in an asyncfunction, and ONLY in an async-function.

随着 ES2017 的出现,这个问题的答案是 async/await。
这是“回调地狱”的 JS 解决方案。Promise 相当于 System.Threading.Tasks.Task。您可以在异步函数中等待 Promise。
与 C# 不同的是,无法在同步函数中调用异步函数。
所以,你可以等待在一个无极异步功能,只有在异步-功能。

async function foo()
{
     return 123;
}

let result = await foo();
console.log(result)

You can use TypeScript or babel to transpile async/await back to ES5 (while IE11 exists).
There's a promise polyfill for IE11.
See ECMA-draft 262or MDNfor closer information.

您可以使用 TypeScript 或 babel 将 async/await 转换回 ES5(当 IE11 存在时)。
IE11 有一个承诺 polyfill。
有关详细信息,请参阅ECMA 草案 262MDN

A good example of promise is the FETCH api.
The fetch-API is good for async/await ajax requests.
Why ? Because if you have to promisify XmlHttpRequest, it looks like this:

promise 的一个很好的例子是 FETCH api。
fetch-API 适用于异步/等待 ajax 请求。
为什么 ?因为如果你必须promisify 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="" />


    <!--
    <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>

回答by fredrik

You can't. There is no equivalent of awaitin JS.

你不能。await在 JS 中没有等价物。

You will have to simulate it by returning false at the invocation of postFormand then upon execution of the callback-function from the AJAX call close the dialog.

您必须通过在调用时返回 false 来模拟它postForm,然后在执行来自 AJAX 调用的回调函数时关闭对话框。

EDIT/UPDATE: Starting with ES2017 there is async/await support - though I don't know if it works in conjunction with jQuery.

编辑/更新:从 ES2017 开始有 async/await 支持 - 虽然我不知道它是否与 jQuery 结合使用。

回答by noseratio

You can use ES6 generators and yieldfeature with Google Traceur Compiler, as I described here.

您可以将 ES6 生成器和yield功能与Google Traceur Compiler 结合使用,正如我在此处所述。

There is some feedbackfrom Traceur team indicating it's a tool of the production quality. It also has experimental supportfor async/await.

一些反馈,从Traceur队表明它是产品质量的工具。它也有实验支持async/await

回答by Jay Wick

See Stefan's answeron using ES2015 async/await now adays.

现在请参阅Stefan关于使用 ES2015 async/await的回答



Original Answer

原答案

You could consider asyncawaitwhich effectively lets you write code as follows

您可以考虑使用asyncawait有效地让您编写如下代码

var foo = async (function() {
    var resultA = await (firstAsyncCall());
    var resultB = await (secondAsyncCallUsing(resultA));
    var resultC = await (thirdAsyncCallUsing(resultB));
    return doSomethingWith(resultC);
});

Instead of the following

而不是以下

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

        });
    });
}

回答by Tieson T.

While this doesn't answer the "what's the equivalent of C#'s await in JavaScript?"question, the code in the question can be made to work rather easily. The bootbox.dialogfunction returns an object, so you can adjust the code shown like so:

虽然这并没有回答“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
            }
        }
    }
});

And then the ajax call gets adjusted to:

然后 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?
        }
    });
}