web-dev-qa-db-ja.com

プロミスを使用する方法、または関数が完了する前にajaxリクエストを完了する方法

ユーザーセッションをチェックして、スタッフかどうかを確認する次の関数があります。今、私はこれを行うより良い方法があることを知っていますが、私はフォーラムソフトウェアと結びついたシンプルなアプリケーションを作ろうとしています。

function isStaff(callback) {
    $.ajax({
        url: url
    }).done(function(data) {
        var session = $.parseJSON(data);
        if (session.is_staff === 1) {
            callback(true);
        } else {
            callback(false);
        }

    });
}

「ポスト」(ハンドルバー)をコンパイルするときに、この関数をこのように使用しているとしましょう。

function compilePost(post) {
    var source = $('#feed-item-template').html();
    var template = Handlebars.compile(source);
    var context = {
        id: post.id,
        content: post.text,
        author: post.author,
        date: $.timeago(post.date),
        staff: function() {
            isStaff(function(response) {
                return response;
            });
        }
    }
    var html= template(context);
    return html;
}

ここでの問題は、ユーザーがスタッフかどうかを確認する要求が、関数が実行されるまで要求を完了しないことです。

私はPromisesがasync:falseの代替手段であることを知っています。この場合、要求が行われ、関数が完了する前に応答が返されます。

しかし、私はこれをどのようにして約束に変換できるのかわかりません。私はそれを学ぼうとしましたが、私はその概念にこだわっています。誰かがこれを私に説明できますか?ありがとう。

12
Jess

まず、compilePost関数を単純化しましょう。この関数は、同期して投稿をコンパイルする方法を知っている必要があります。 isStaffフェッチを単純な引数に変更しましょう。

function compilePost(post, isStaff) {
    var source = $('#feed-item-template').html();
    var template = Handlebars.compile(source);
    var context = {
        id: post.id,
        content: post.text,
        author: post.author,
        date: $.timeago(post.date),
        staff: isStaff
    }

    var html= template(context);
    return html;
}

次に、単一の目的で新しいメソッドを作成しましょう。ユーザーがスタッフのメンバーであるかどうかを確認します。

function checkForStaffMemebership() {
    return new Promise(function (resolve, reject) {
        $.ajax({
            url: url,
            success: function (data) {
                var session = $.parseJSON(data);
                if (session.is_staff === 1) {
                    resolve(true);
                } else {
                    resolve(false);
                }
            }
        });
    });
}

この関数は、ajaxサーバーへの元の呼び出しを、$.ajax呼び出しはサーバーから応答を取得し、ユーザーがスタッフメンバーであるかどうかにかかわらず、Promiseは回答で解決します。

これで、プロセスを調整する別の関数を記述できます。

function compilePostAsync(post) {
    return checkForStaffMemebership()
        .then(function (isStaff) {
            return compilePost(post, isStaff);
        });
}

compilePostAsyncは、ユーザーがスタッフであるかどうかを調べます。その後、投稿を編集しています。

compilePostAsyncはpromiseを返すため、以前は次のようなものがあったことに注意してください。

element.innerHTML = compilePost(post);

ここで、次のように変更する必要があります。

compilePostAsync(post).then(function (compiledPost) {
    element.innerHTML = compiledPost;
});

いくつかのメモ:

  1. これは単なる例であり、確かにいくつかのことを見落とします(たとえば、適切なエラー処理)
  2. isStaffおよびcheckForStaffMemebership(オリジナルおよび新規)は引数を取得しません。userIdまたは必要なその他のデータを渡す方法を理解していると思います。
  3. 約束について読んでください。これは便利なツールです。たとえば、Webにはそれについて多くのデータがあります。 [〜#〜] mdn [〜#〜]
17
Gilad Artzi

documentation に従って、すでにpromiseを実装しているpromiseでajaxをラップする必要はありません。代わりに、以下で説明するように応答をチェーンします。

JQuery 1.5の時点で$ .ajax()によって返されたjqXHRオブジェクトは、Promiseインターフェースを実装し、Promiseのすべてのプロパティ、メソッド、および動作を提供します(詳細については、遅延オブジェクトを参照してください)。

レスポンスをチェーンすることで以下のようなことができます:

function isStaff(url, post) {
    return $.ajax({
        url: url,
        dataType:"json"
    }).then(function(resp){
        //resp = $.parseJSON(resp); /*You dont require this if you have respose as JSON object. Just Specify it in 'dataType'*/
        var source = $('#feed-item-template').html();
        var template = Handlebars.compile(source);
        var context = {
            id: post.id,
            content: post.text,
            author: post.author,
            date: $.timeago(post.date),
            staff: resp.is_staff === 1 ? true : false
        };

        return template(context);
    });
}

isStaff(url, post).done(function(template){
    /*Your compiled template code is available here*/
}).fail(function(jqXHR, textStatus, errorThrown){
   console.log("Error:"+textStatus);
});

注:error callbacks も実装してください。何がうまくいかなかったのかは決してわからないからです:)


$ .deferを使用したpromiseに関する簡単な説明:

理解のために、私はあなたの要件に似た Fiddle を作成しました。

説明:

基本的にPromiseは、非同期JSコードの同期実行を実現するために導入されています。

非同期または非同期コードとはどういう意味ですか?

実行されるコードは、即時ではない任意の時点で値を返す可能性があります。このステートメントをサポートする有名な例は、jquery ajaxです。

なぜ必要なのですか?

Promise実装は、開発者が応答を非同期コードブロックに依存する同期コードブロックを実装するのに役立ちます。 ajax呼び出しのように、サーバーにデータ文字列を要求するときに、同期コードがそれを操作してロジックを実行し、UIを更新するために、サーバーが応答データ文字列でサーバーに応答するまで待つ必要があります。

これに従ってください リンク 著者が詳細な例で説明したところ。

PS:Jquery $.deferpromiseをまったく異なる方法で実装またはラップします。どちらも同じ目的で使用されます。

1
Nirus
let basedataset = {}
let ajaxbase = {};
//setting api Urls
apiinterface();

function apiinterface() {
    ajaxbase.createuser = '/api/createuser'
}
//setting up payload for post method
basedataset.email = profile.getEmail()
basedataset.username = profile.getGivenName()
//setting up url for api 
ajaxbase.url = ajaxbase.createuser
ajaxbase.payload = basedataset;

//reusable promise based approach 
basepostmethod(ajaxbase).then(function(data) {
    console.log('common data', data);
}).catch(function(reason) {
    console.log('reason for rejection', reason)
});
//modular ajax (Post/GET) snippets
function basepostmethod(ajaxbase) {

    return new Promise(function(resolve, reject) {
        $.ajax({
            url: ajaxbase.url,
            method: 'post',
            dataType: 'json',
            data: ajaxbase.payload,
            success: function(data) {
                resolve(data);
            },
            error: function(xhr) {
                reject(xhr)
            }

        });
    });
}
0
Rizwan Patel

Jsで非同期待機を使用するソリューションは次のようになります。

async function getMyAjaxCall() {
  const someVariableName = await ajaxCallFunction();
}

function getMyAjaxCall() {
    return $.ajax({
    type: 'POST',
    url: `someURL`,
    headers: {
      'Accept':'application/json',
  },
    success: function(response) {
// in case you need something else done.
    }
    });
}
0
FabricioG