簡體   English   中英

什么是C#在javascript / jquery等待?

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

我正在使用一個名為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;
}

JavaScript(當前)沒有等同於async / await的語言。 各種各樣的promise庫可供JavaScript使用,它們大致相當於Task類型。 這是原始回調之上的一個很好的步驟,但除了最簡單的場景之外,你最終還是會遇到笨拙的嵌套或回調意大利面。

JavaScript ECMAScript 6(“Harmony”)預計將包含生成器 ES6有望在今年晚些時候正式上市,但可能需要一段時間才能安全地假設用戶的瀏覽器支持發電機。

通過發電機與承諾相結合 ,可以實現真正的async / await等同。

我認為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僅公開附加其他處理程序或確定狀態( thendonefailalwayspipeprogressstate )所需的延遲方法,但不會resolveWith更改狀態的方法( resolverejectnotifyresolveWithrejectWith ,和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
});

你不能。 在JS中沒有等效的await

你必須通過在postForm的調用時返回false來模擬它,然后在從AJAX調用執行回調函數時關閉對話框。

編輯/更新:從ES2017開始有async / await支持 - 雖然我不知道它是否與jQuery一起使用。

隨着ES2017的出現,這個問題的答案是async / await。
這是“回調地獄”的JS解決方案。 Promise相當於System.Threading.Tasks.Task。 您可以在異步函數中等待Promise。
與C#不同,無法在同步函數中調用異步函數。
所以,你可以等待異步功能的承諾,只有在異步 -功能。

async function foo()
{
     return 123;
}

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

您可以使用TypeScript或babel將async / await轉換回ES5(當IE11存在時)。
IE11有一個承諾polyfill。
有關詳細信息,請參閱ECMA草案262MDN

一個很好的例子是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的功能與谷歌Traceur編譯器 ,我描述這里

Traceur團隊提供了一些反饋 ,表明它是生產質量的工具。 它還為async/await提供實驗支持

請參閱Stefan關於使用ES2015異步/等待現在的答案


原始答案

您可以考慮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?
        }
    });
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM