我正在使用 Revealing Module 模式编写一个自定义库来处理特定的 cookie,并尝试使用 jQuery Promise 作为 cookie 的“Getter”函数的返回值,以防止调用该函数的人在初始设置之前更新该函数,从而保持同步。
见下文:
/**
* Handles the state cookie for a browser.
*
* JS DEPENDENCIES:
* - jQuery Cookie plugin
*
* DOM DEPENDENCIES:
* - None
*
*/
var myUtilities = myUtilities || {};
myUtilities.stateManager = (function() {
var cookieName = 'us_state';
/**
* Find geolocation state / set cookie
* The passed deferred object only gets set as resolved if the AJAX response has the resulting data we need. Otherwise it is rejected.
*
* @param {Object} position Passed from 'navigator.geolocation.getCurrentPosition'. Contains browser's approximation of its current latitude+longitude.
* @return {Object} The promise resolution (resolve or reject). Resolved has a String of state abbreviation in lowecase. Rejected is empty.
*/
function _getLocation(position) {
var latitude = position.coords.latitude,
longitude = position.coords.longitude;
/* TEST VALUES */
/* CA coords */
// latitude = '37.7833';
// longitude = '-122.4167';
/* AZ coords */
// latitude = '33.45';
// longitude = '-112.0667';
// If this errors out due to CORS issue (or similar issue) of if the return value doesn't match then we set the promise to reject
return $.ajax({
url: 'https://maps.googleapis.com/maps/api/geocode/json?latlng=' + latitude + ',' + longitude,
dataType: "json"
});
}
/**
* Defer for getCurrentPosition callback
* Create an anonymous function to handle success; accepts a Position object as argument, and calls _getLocation() passing in the position object.
* When AJAX promise is complete evalute the data to find the state abbreviation.
* Reject a failed call for getCurrentPosition (user did not allow/timeout on browser's request to use geolocation)
*
* @var {Object} $df jQuery Deferred object
* @return {Object} jQuery Promise
*/
function _deferGetLocation() {
var $df = $.Deferred();
if ("geolocation" in navigator) {
navigator.geolocation.getCurrentPosition(
function(position) {
_getLocation(position)
.then(function(data) {
if (data.length !== 0) {
var result = data.results[0],
address = '',
state = '';
// A for-loop is used because the response changes based on the address that Google API returns (a single search into a specific part of the data Object is not always successful evne though the data may be in there)
for (var i = 0, len = result.address_components.length; i < len; i++) {
address = result.address_components[i];
if (address.types.indexOf('administrative_area_level_1') >= 0) {
// By returning here we exit the loop as soon as we get a match, like a 'break'
$df.resolve(address.short_name.toLowerCase());
break;
}
}
}
});
});
} else {
$df.reject();
}
return $df.promise();
}
/**
* Either get the get cookie or set it now.
* If the cookie exists we resolve the promise immediately, else wait for the geolocation to be resolved, set state cookie and resolve.
*
* @var {Object} $df jQuery Deferred object
* @var {String} stateString state, 2 character abbreviation format
* @return {Object} Promise with a String for the callback (two-character value indicating which state the user is in)
*/
function _getStateCookie(){
var $df = $.Deferred();
if ($.cookie(cookieName)) {
$df.resolve($.cookie(cookieName));
} else {
_deferGetLocation()
.then(function(state) {
$df.resolve(_setStateCookie(state));
});
}
return $df.promise();
}
/**
* Set the 'cookieName' cookie to a desired state, or default to 'co'
*
* @param {String} state The value of the cookie as a 2 character length state abbreviation
* @param {Datetime} expirationDate Days until the cookie expires
*/
function _setStateCookie (state, expirationDate){
state = ( typeof state == 'undefined' || !_isValidState(state) ) ? 'co' : state;
expirationDate = ( typeof expirationDate == 'undefined' ) ? 365 : expirationDate;
$.cookie(cookieName, state, { path: '/', expires: expirationDate });
// Offer an event listener for this cookie
$(document).trigger('state-utility.cookieChange');
return state;
}
/**
* Validates a given string against our predetermined "valid states" (AZ, CA, CA).
* Returns true if valid, false otherwise.
* Case-sensitive, AZ == az -> false
*
* @param {String} state A value to be compared for valid state
* @return {Boolean} True if valid, false otherwise
*/
function _isValidState(state) {
return (state == 'az' || state == 'ca' || state == 'ca');
}
function _isCookieSet() {
return ($.cookie(cookieName) && _isValidState($.cookie(cookieName)));
}
return {
// Using a Promise so that multiple calls to _getStateCookie() are handled synchronously
getStateCookie : function() {
return _getStateCookie().then( function(state) { return state; });
},
setStateCookie : function(state, expirationDate) {
return _setStateCookie(state, expirationDate);
},
updateStateElement : function(target) {
return _updateStateElement(target);
},
isValidState : function(state) {
return _isValidState(state);
},
isCookieSet : function() {
return _isCookieSet();
}
};
})();
<script src="https://raw.githubusercontent.com/carhartl/jquery-cookie/master/src/jquery.cookie.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
当尝试使用myUtilities.stateManager.getStateCookie()
. 我希望此调用返回最近适用状态的两个字符的字符串。相反,我得到了返回的 Promise 对象。
为什么返回 Promise 而不是字符串,需要更改哪些内容才能返回所需的字符串?
感谢您的时间。