jQuery: 保存异步调用结果以备后用?
jQuery: save asynchronous call result to be used later?
我有这个实现:
instance.web_calendar.CalendarView.include({
handle_special_dates: function(date, cell){
var def = $.Deferred(),
model = new instance.web.Model('calendar.special');
model.call('get_special_dates').then(function(result){
// Transform date strings into date obj valueOf result.
var new_obj = {}
for (key in result){
if (result.hasOwnProperty(key)){
var dt_value = new Date(key).valueOf();
// Set new key as date.ValueOf() and use
// special date name as value.
new_obj[dt_value] = result[key]
}
}
return new_obj;
}).then(function(result){
// We stringify value, because object stringifies keys
// automatically.
var dt_value = String(date.valueOf())
// Check if date value is in special dates keys.
// We check for -1, because it actually returns index,
// not a boolean value.
if ($.inArray(dt_value, Object.keys(result)) != -1){
var div = $(
'<div />',
{
"class": 'fc-special-day',
text: result[dt_value]
}
)
cell.children('div').prepend(div)
// Set special day background
cell.addClass('fc-special-background')
}
})
return def;
},
get_fc_init_options: function(){
var self = this;
fc_options = this._super()
if (this.special_dates){
return $.extend({}, fc_options, {
dayRender: function(date, cell){
self.handle_special_dates(date, cell)
}
});
} else {
return fc_options;
}
},
})
}
handle_special_dates
系统后端定义的函数调用方法(这是异步调用),解析结果并使用它来检查我们是否需要修改日历的cell
。
问题是两个 then
部分的调用次数与要检查的单元格一样多。所以这有点笨拙,因为我只需要调用后端一次,然后对所有单元格使用结果。
基本上第一个 then
(调用 get_special_dates
后端方法的部分)应该只调用一次。我试图分离该功能,但它被调用的时间晚于 dayRender
需要它的时间。也就是说,它永远不会在需要的时候调用:).
有什么方法可以等待第一部分完成而不是像现在这样调用它吗?我的意思是它是异步调用,但现在我猜它比同步更慢。
P.S。我知道 JS 中有新的 Promise
功能,但此版本中的 Odoo 目前使用 jQuery 延迟,所以我也在使用它。
更新
为了更好的说明情况,我会尽量描述结构,目前做了什么,有什么问题。
这个系统有两部分,后端(由Python管理)和前端(Javascript)。
后端管理前端可以使用的数据。具体来说,后端有一个方法叫get_special_dates
。它 return 的日期是在特定的 table 中输入的名称,称为 calendar_special
。因此,如果有人输入任何此类日期,它将 return 其日期字符串表示(和名称)。例如,我们可以输入日期 2017-04-16
并将其命名为 Easter
。
现在,当 Javascript 部分加载日历界面时,它会检查所有当前可见的日历日期并与 return 由 get_special_dates
编辑的日期进行比较。如果比较的日期匹配,它将在日历中标记它们。
但问题是,get_special_dates
现在被调用 的次数与每个 date/cell 对的检查次数一样多。假设我们在一个月中有 30 个日期并且我们看到那个月的 30 个日期,它会调用 get_special_dates
30 次,而实际上 只调用一次 就足够了(因为来自后端的日期对于所有 date/cell 对检查都是相同的)。但我需要保存结果以供所有 date/cell 对重复使用(或其他适合 deferred
的方式)。
基本上它会检查每个可见的日历日期并与后端输入的日期进行比较。
也许这张图片更能说明此功能的工作原理。绿色背景的日期实际上是在后台作为特殊日期输入的日期。
你问的很有效,"how do I cache a promise?"。
简单的答案是 "assign it to a member in a suitable scope, from which it can be accessed wherever needed."
这里,a "member in a suitable scope"(不一定是唯一一个)是handle_special_dates()
是一个属性的对象,其中(除非 handle_special_dates()
以一种奇怪的方式调用)将是 handle_special_dates()
中的 this
。
除了缓存 promise 之外,您还可以通过在缓存点链接两个 then 中的第一个来仅执行一次 new_obj
转换。
specialDatesPromise: null, // not strictly necessary but makes the cache overt.
handle_special_dates: function(date, cell) {
// if promise doesn't already exist, call() and cache
if(!this.specialDatesPromise) {
this.specialDatesPromise = (new instance.web.Model('calendar.special')).call('get_special_dates')
.then(function(specialDates) {
// for economy of effort, perform transform at point of caching
var new_obj = {};
$.each(specialDates, function(key, value) {
new_obj[new Date(key).valueOf()] = value;
});
return new_obj;
});
}
// Now use the cached promise - it may be newly or previously cached - doesn't matter which.
return this.specialDatesPromise.then(function(result) {
var dt_value = String(date.valueOf());
if (result[dt_value] !== undefined) {
cell.addClass('fc-special-background').children('div').prepend($('<div/>', {
'class': 'fc-special-day',
'text': result[dt_value]
}));
}
});
},
除了我 mistakes/misunderstandings 之外,进一步的简化应该可行。
注意,不需要 jQuery.Deferred()
因为 .call('get_special_dates')
returns 一个可行的承诺。
我有这个实现:
instance.web_calendar.CalendarView.include({
handle_special_dates: function(date, cell){
var def = $.Deferred(),
model = new instance.web.Model('calendar.special');
model.call('get_special_dates').then(function(result){
// Transform date strings into date obj valueOf result.
var new_obj = {}
for (key in result){
if (result.hasOwnProperty(key)){
var dt_value = new Date(key).valueOf();
// Set new key as date.ValueOf() and use
// special date name as value.
new_obj[dt_value] = result[key]
}
}
return new_obj;
}).then(function(result){
// We stringify value, because object stringifies keys
// automatically.
var dt_value = String(date.valueOf())
// Check if date value is in special dates keys.
// We check for -1, because it actually returns index,
// not a boolean value.
if ($.inArray(dt_value, Object.keys(result)) != -1){
var div = $(
'<div />',
{
"class": 'fc-special-day',
text: result[dt_value]
}
)
cell.children('div').prepend(div)
// Set special day background
cell.addClass('fc-special-background')
}
})
return def;
},
get_fc_init_options: function(){
var self = this;
fc_options = this._super()
if (this.special_dates){
return $.extend({}, fc_options, {
dayRender: function(date, cell){
self.handle_special_dates(date, cell)
}
});
} else {
return fc_options;
}
},
})
}
handle_special_dates
系统后端定义的函数调用方法(这是异步调用),解析结果并使用它来检查我们是否需要修改日历的cell
。
问题是两个 then
部分的调用次数与要检查的单元格一样多。所以这有点笨拙,因为我只需要调用后端一次,然后对所有单元格使用结果。
基本上第一个 then
(调用 get_special_dates
后端方法的部分)应该只调用一次。我试图分离该功能,但它被调用的时间晚于 dayRender
需要它的时间。也就是说,它永远不会在需要的时候调用:).
有什么方法可以等待第一部分完成而不是像现在这样调用它吗?我的意思是它是异步调用,但现在我猜它比同步更慢。
P.S。我知道 JS 中有新的 Promise
功能,但此版本中的 Odoo 目前使用 jQuery 延迟,所以我也在使用它。
更新
为了更好的说明情况,我会尽量描述结构,目前做了什么,有什么问题。
这个系统有两部分,后端(由Python管理)和前端(Javascript)。
后端管理前端可以使用的数据。具体来说,后端有一个方法叫get_special_dates
。它 return 的日期是在特定的 table 中输入的名称,称为 calendar_special
。因此,如果有人输入任何此类日期,它将 return 其日期字符串表示(和名称)。例如,我们可以输入日期 2017-04-16
并将其命名为 Easter
。
现在,当 Javascript 部分加载日历界面时,它会检查所有当前可见的日历日期并与 return 由 get_special_dates
编辑的日期进行比较。如果比较的日期匹配,它将在日历中标记它们。
但问题是,get_special_dates
现在被调用 的次数与每个 date/cell 对的检查次数一样多。假设我们在一个月中有 30 个日期并且我们看到那个月的 30 个日期,它会调用 get_special_dates
30 次,而实际上 只调用一次 就足够了(因为来自后端的日期对于所有 date/cell 对检查都是相同的)。但我需要保存结果以供所有 date/cell 对重复使用(或其他适合 deferred
的方式)。
基本上它会检查每个可见的日历日期并与后端输入的日期进行比较。
也许这张图片更能说明此功能的工作原理。绿色背景的日期实际上是在后台作为特殊日期输入的日期。
你问的很有效,"how do I cache a promise?"。
简单的答案是 "assign it to a member in a suitable scope, from which it can be accessed wherever needed."
这里,a "member in a suitable scope"(不一定是唯一一个)是handle_special_dates()
是一个属性的对象,其中(除非 handle_special_dates()
以一种奇怪的方式调用)将是 handle_special_dates()
中的 this
。
除了缓存 promise 之外,您还可以通过在缓存点链接两个 then 中的第一个来仅执行一次 new_obj
转换。
specialDatesPromise: null, // not strictly necessary but makes the cache overt.
handle_special_dates: function(date, cell) {
// if promise doesn't already exist, call() and cache
if(!this.specialDatesPromise) {
this.specialDatesPromise = (new instance.web.Model('calendar.special')).call('get_special_dates')
.then(function(specialDates) {
// for economy of effort, perform transform at point of caching
var new_obj = {};
$.each(specialDates, function(key, value) {
new_obj[new Date(key).valueOf()] = value;
});
return new_obj;
});
}
// Now use the cached promise - it may be newly or previously cached - doesn't matter which.
return this.specialDatesPromise.then(function(result) {
var dt_value = String(date.valueOf());
if (result[dt_value] !== undefined) {
cell.addClass('fc-special-background').children('div').prepend($('<div/>', {
'class': 'fc-special-day',
'text': result[dt_value]
}));
}
});
},
除了我 mistakes/misunderstandings 之外,进一步的简化应该可行。
注意,不需要 jQuery.Deferred()
因为 .call('get_special_dates')
returns 一个可行的承诺。