遍历 ajax 调用的最佳方法是什么
What's the best way to loop through ajax calls
我正在使用 Sharepoint,并且我有一个在网站集中创建列表的应用程序(不是应用程序!)。创建列表不是问题。
我不想创建 15 列并将它们添加到默认视图。我准备了一个 "config",其中包含列表及其字段的信息。
var ChangeRequestLogListConfig = {
listName: 'ChangeRequestLog',
fields: [
{ 'FieldTypeKind': 8, 'Title': 'STC Relevant', 'InternalName': 'STCrelevant', 'StaticName': 'STCrelevant' },
{ 'FieldTypeKind': 3, 'Title': 'Description/Reason', 'InternalName': 'DescriptionReason', 'StaticName': 'DescriptionReason' },
{ 'FieldTypeKind': 6, 'Title': 'Source of Change', 'InternalName': 'SourceOfChange', 'StaticName': 'SourceOfChange', 'Choices': { 'results': ['customer', 'internal'] } },
//12 more objects like the above
]
}
我们遇到了问题:其余资源 .../ViewFields/AddViewField
和 .../fields
(使用 http post 创建新资源)只支持一个参数,这意味着我必须做2x15 ajax 次调用。
执行所有这 30 个操作然后执行最终回调的正确方法是什么?我当然知道如何遍历字段数组,我只是不知道如何以正确的方式构建最终回调。
更新/跟进
在一些答案的帮助下,我设法构建了以下代码:
var spExecutor = new SP.RequestExecutor(_spPageContextInfo.siteAbsoluteUrl);
var requestUrl = _spPageContextInfo.siteAbsoluteUrl + "/_api/SP.AppContextSite(@target)/web/Lists/getbytitle('" + listConfig.listName + "')/fields?@target='" + hostWebUrl + "'";
//map field configs to promises
var promises = listConfig.fields.map(fieldConfig => {
return spExecutor.executeAsync({
url: requestUrl,
method: "POST",
body: JSON.stringify(fieldConfig),
headers: {
"accept": "application/json;odata=verbose",
"content-type": "application/json; odata=verbose"
},
error: err => console.log(err)
});
});
//Wait for all calls to be done
$.when.apply($, promises).then(callbackFn);
正如您可能已经看到的,我没有使用 $.ajax
,而是 SP.RequestExecutor
。
问题:return 的承诺方式与 jQuery 的 ajax 不同。这会导致计时问题(--> 15 Calls at once,浏览器大多只支持 4 个并行调用)。上面的代码有效,如果我设置断点并在调用之间等待 1-2 秒,它会按预期创建所有字段。
我的后续问题:如何等待第一次调用 init 的完成,然后是第二个,然后是第三个等等?
我不确定我是否以正确的方式使用承诺。
使用.map
将每个字段转换成Promise
:
var promises = ChangeRequestLogListConfig.fields.map(
item => $.ajax( ... )
);
然后$.when
等待他们全部完成:
$.when.apply($, promises).then( ... );
请注意,这将在您的浏览器允许的范围内并行启动尽可能多的 AJAX 请求 - 通常是四个。
EDIT 因为你说过你实际上想要 AJAX 查询到 运行 系列(以避免服务器 409 错误)我的版本addFieldsToList
函数如下所示:
function addFieldsToList(listConfig) {
return listConfig.fields.reduce(function(promise, field) {
return promise.then(executeRequest(field, listConfig.listName));
}, Promise.resolve(null));
}
避免传递回调,因为此函数的 return 值本身就是一个 Promise
,您可以链接:
addFieldsToList(myConfig).then(callback);
最后我这样做了:
//Promise returning request
function executeRequest(fieldConfig, listName) {
return function () {
return new Promise(function (resolve, reject) {
var requestUrl = _spPageContextInfo.siteAbsoluteUrl + "/_api/SP.AppContextSite(@target)/web/Lists/getbytitle('" + listName + "')/fields?@target='" + riskapp.utils.getSpHostUrl() + "'";
var spExecutor = new SP.RequestExecutor(_spPageContextInfo.siteAbsoluteUrl);
spExecutor.executeAsync({
url: requestUrl,
method: "POST",
body: JSON.stringify(fieldConfig),
headers: {
"accept": "application/json;odata=verbose",
"content-type": "application/json; odata=verbose"
},
success: resolve,
error: reject
});
});
};
}
//Add fields to list according to config
function addFieldsToList(listConfig, callback) {
//Prepare empty/resolved promise to iterate later
var promise = Promise.resolve(null);
//Loop through every field
$.each(listConfig.fields, function (i, field) {
promise = promise.then(executeRequest(listConfig[field], listConfig.listName));
});
//execute callback when all fields are created
promise.then(callback);
}
这会按顺序执行所有调用,而不是同时执行。
我正在使用 Sharepoint,并且我有一个在网站集中创建列表的应用程序(不是应用程序!)。创建列表不是问题。 我不想创建 15 列并将它们添加到默认视图。我准备了一个 "config",其中包含列表及其字段的信息。
var ChangeRequestLogListConfig = {
listName: 'ChangeRequestLog',
fields: [
{ 'FieldTypeKind': 8, 'Title': 'STC Relevant', 'InternalName': 'STCrelevant', 'StaticName': 'STCrelevant' },
{ 'FieldTypeKind': 3, 'Title': 'Description/Reason', 'InternalName': 'DescriptionReason', 'StaticName': 'DescriptionReason' },
{ 'FieldTypeKind': 6, 'Title': 'Source of Change', 'InternalName': 'SourceOfChange', 'StaticName': 'SourceOfChange', 'Choices': { 'results': ['customer', 'internal'] } },
//12 more objects like the above
]
}
我们遇到了问题:其余资源 .../ViewFields/AddViewField
和 .../fields
(使用 http post 创建新资源)只支持一个参数,这意味着我必须做2x15 ajax 次调用。
执行所有这 30 个操作然后执行最终回调的正确方法是什么?我当然知道如何遍历字段数组,我只是不知道如何以正确的方式构建最终回调。
更新/跟进
在一些答案的帮助下,我设法构建了以下代码:
var spExecutor = new SP.RequestExecutor(_spPageContextInfo.siteAbsoluteUrl);
var requestUrl = _spPageContextInfo.siteAbsoluteUrl + "/_api/SP.AppContextSite(@target)/web/Lists/getbytitle('" + listConfig.listName + "')/fields?@target='" + hostWebUrl + "'";
//map field configs to promises
var promises = listConfig.fields.map(fieldConfig => {
return spExecutor.executeAsync({
url: requestUrl,
method: "POST",
body: JSON.stringify(fieldConfig),
headers: {
"accept": "application/json;odata=verbose",
"content-type": "application/json; odata=verbose"
},
error: err => console.log(err)
});
});
//Wait for all calls to be done
$.when.apply($, promises).then(callbackFn);
正如您可能已经看到的,我没有使用 $.ajax
,而是 SP.RequestExecutor
。
问题:return 的承诺方式与 jQuery 的 ajax 不同。这会导致计时问题(--> 15 Calls at once,浏览器大多只支持 4 个并行调用)。上面的代码有效,如果我设置断点并在调用之间等待 1-2 秒,它会按预期创建所有字段。
我的后续问题:如何等待第一次调用 init 的完成,然后是第二个,然后是第三个等等? 我不确定我是否以正确的方式使用承诺。
使用.map
将每个字段转换成Promise
:
var promises = ChangeRequestLogListConfig.fields.map(
item => $.ajax( ... )
);
然后$.when
等待他们全部完成:
$.when.apply($, promises).then( ... );
请注意,这将在您的浏览器允许的范围内并行启动尽可能多的 AJAX 请求 - 通常是四个。
EDIT 因为你说过你实际上想要 AJAX 查询到 运行 系列(以避免服务器 409 错误)我的版本addFieldsToList
函数如下所示:
function addFieldsToList(listConfig) {
return listConfig.fields.reduce(function(promise, field) {
return promise.then(executeRequest(field, listConfig.listName));
}, Promise.resolve(null));
}
避免传递回调,因为此函数的 return 值本身就是一个 Promise
,您可以链接:
addFieldsToList(myConfig).then(callback);
最后我这样做了:
//Promise returning request
function executeRequest(fieldConfig, listName) {
return function () {
return new Promise(function (resolve, reject) {
var requestUrl = _spPageContextInfo.siteAbsoluteUrl + "/_api/SP.AppContextSite(@target)/web/Lists/getbytitle('" + listName + "')/fields?@target='" + riskapp.utils.getSpHostUrl() + "'";
var spExecutor = new SP.RequestExecutor(_spPageContextInfo.siteAbsoluteUrl);
spExecutor.executeAsync({
url: requestUrl,
method: "POST",
body: JSON.stringify(fieldConfig),
headers: {
"accept": "application/json;odata=verbose",
"content-type": "application/json; odata=verbose"
},
success: resolve,
error: reject
});
});
};
}
//Add fields to list according to config
function addFieldsToList(listConfig, callback) {
//Prepare empty/resolved promise to iterate later
var promise = Promise.resolve(null);
//Loop through every field
$.each(listConfig.fields, function (i, field) {
promise = promise.then(executeRequest(listConfig[field], listConfig.listName));
});
//execute callback when all fields are created
promise.then(callback);
}
这会按顺序执行所有调用,而不是同时执行。