web-dev-qa-db-ja.com

カスタム関数でjQuery promise / deferredを使用するにはどうすればよいですか?

navigator.geolocationを通じて位置を取得する関数があります。

var getLocation = function( callback ){

    navigator.geolocation.getCurrentPosition( callback || function( position ){

        // Stuff with geolocation

    });

};

JQueryの Deffered オブジェクトを使用してこの関数をチェーンできるようにしたいのですが、まだDefferedの概念と使用法を把握できていません。

これに似たものを探しています疑似コード

getLocation().then(function(){
    drawMarkerOnMap();
});

この構文は、後方にめくったりコードに溺れたりせずに可能ですか?

35
hitautodestruct

新しい据え置きオブジェクトをインスタンス化して、関数からオブジェクト(またはそのプロミス)を返す必要があります。 .resolveメソッドが応答を受け取ったら、

var getLocation = function() {
    var deferred = new $.Deferred();

    navigator.geolocation.getCurrentPosition(function( position ){
        // Stuff with geolocation
        deferred.resolve(position);
    });

    // return promise so that outside code cannot reject/resolve the deferred
    return deferred.promise();
};

使用法:

getLocation().then(drawMarkerOnMap);

参照jQuery.Deferred


補遺

インターフェイスをシンプルに保つために、両方のアプローチ(遅延オブジェクトとコールバックを関数に渡す)を使用しないことをお勧めします。ただし、下位互換性を維持する必要がある場合は、渡されたコールバックを遅延オブジェクトに登録するだけです。

var getLocation = function(callback) {
    var deferred = new $.Deferred();

    if ($.isFunction(callback)) {
        deferred.then(callback);
    }

    navigator.geolocation.getCurrentPosition(function( position ){
        // Stuff with geolocation
        deferred.resolve(position);
    });

    // return promise so that outside code cannot reject/resolve the deferred
    return deferred.promise();
};
62
Felix Kling

タイトルにjQueryと書いてあるのは知っていますが、この質問をしたとき、Webに対する約束は新しく、jQueryは事実上のライブラリでした。 jQueryを使用しない、より現代的な答えを次に示します。

ネイティブを使用 Promise

すべて 最新のブラウザー (IE11以下を除く; 必要に応じてポリフィルを使用する )により、ネイティブのPromise構成を使用できます。

_let getLocation = () => {

  return new Promise( ( resolve, reject ) => {

    try {
      navigator.geolocation.getCurrentPosition( position => {
        resolve( position )
      })
    } catch ( err ) {
      reject( err )
    }

  })

};
_

使用法:

_let runGetLocation = () => { getLocation().then( position => console.log( position ) ) }
_

.then()の代わりにES2016 async/awaitを使用することもできます:

_let runGetLocation = async () => {

  try {
    let position = await getLocation()
    console.log( position )
  } catch ( err ) { console.log( err ) }

}
_
1
hitautodestruct

上記の例は私に役立つものでしたが、コンセプトを理解するためにもう少し読む必要がありました。

以下は、コードに基づいた例です。コードに戻ったときに私を支援するコメントが含まれています。うまくいけば、このStackoverflowの質問を読んでいる人がいます。

/* promise based getFilter to accommodate getting surrounding suburbs */
oSearchResult.fPromiseOfFilterSetting = function fPromiseOfFilterSetting(sId) {
    var self = this;
    self.oPromiseCache = self.oPromiseCache || {}; // creates a persistent cache 
                                                   // across function calls
    var oDeferred = $.Deferred(); // `new` keyword is optional
    var oPromise = oDeferred.promise();

    // leverage the cache (it's ok if promise is still pending), you can key
    if (self.oPromiseCache[sId] !== undefined) {
        return self.oPromiseCache[sId];
    }
    else {
        self.oPromiseCache[sId] = oPromise;
    }

    // do our asynchronous action below which at some point calls
    // defered.resolve(...) and hence complete our promise
    $.cmsRestProxy.doAjaxServiceRequest('ocms_searchProperties_Extension', {
        action : 'getSurroundingSuburbs',
        sSuburbIds : 'a0RO0000003BwWeMAK'
    }, function(result, json) {
        console.log("doAjaxServiceRequest(
                       'ocms_searchProperties_Extension')", json);
        oDeferred.resolve(json); // `json` is our result and `.resolve(json)` 
                                 // passes the value as first argument to 
                                 // the `oPromise.done`, `oPromise.fail` 
                                 // and `oPromise.always` callback functions
    })

    // We can now return the promise or attach optional `oPromise.done`,
    // `oPromise.fail`, and `oPromise.always` callbacks which will execute first
    // in the chain.
    //
    // Note that `oPromise.then(doneCallback, failCallback, alwaysCallback)`
    // is short form for the below
    oPromise.done(function(value) { // returned by promise.resolve(...); call
        console.log('will run if this Promise is resolved.', value);
    })
    oPromise.fail(function(value) {
        console.log("will run if this Promise is rejected.", value);
    });
    oPromise.always(function(value) {
        console.log("this will run either way.", value);
    });

    // return a promise instead of deferred object so that
    // outside code cannot reject/resolve it
    return oPromise;
}

// then to use one would do
oSearchResult.fPromiseOfFilterSetting().done(function(value) {alert(value)});

// or using $.when chaining
$.when(
    oSearchResult.fPromiseOfFilterSetting()
)
.done(
      function fDoneCallback(arg1, arg2, argN) {
          console.debug(arguments) // `arguments` is an array of all args collected
      }
);
1