Асинхронное программирование в случае надстроек Office
Важно!
Эта статья относится к общим API, модели API JavaScript для Office, которая была представлена в Office 2013. Эти API-интерфейсы включают такие компоненты, как пользовательский интерфейс, диалоговые окна и параметры клиентов, общие для нескольких типов приложений Office. Надстройки Outlook используют только общие API, в частности подмножество API, предоставленных в объекте Mailbox.
Вы должны использовать общие API только в сценариях, которые не поддерживаются API-интерфейсами для определенных приложений. Сведения о том, как использовать общие API вместо API для определенных приложений, см. в статье Общие сведения об API JavaScript для Office.
Почему в API Надстройки Office используется асинхронное программирование? JavaScript — это однопоточный язык. Если скрипт вызывает длительный синхронный процесс клиента Office, все последующие скрипты блокируются до завершения этого процесса. Асинхронный режим обеспечивает быстрое и быстрое реагирование надстроек Office.
Имена всех асинхронных методов в общих API заканчиваются на "Async", например Document.getSelectedDataAsync
методы , Binding.getDataAsync
или Item.loadCustomPropertiesAsync
. При вызове асинхронного метода он выполняется немедленно. Остальная часть скрипта продолжается, пока операция завершается на стороне клиента. Необязательная функция обратного вызова, передаваемая в асинхронный метод, запускается, как только данные или запрошенная операция будут готовы. Обычно это происходит быстро, но может быть небольшая задержка.
На следующей схеме показан поток асинхронного метода, который считывает данные, выбранные пользователем в документе. При выполнении асинхронного вызова поток JavaScript может выполнять дополнительную обработку на стороне клиента (хотя ни один из них не показан на схеме). Когда возвращается метод Async, обратный вызов возобновляется в потоке. Затем надстройка может получить доступ к данным, выполнить с ним что-то и отобразить результат. Шаблон одинаков на разных платформах.
Запись функции обратного вызова для асинхронного метода
Функция обратного вызова, передаваемая в качестве аргумента обратного вызова методу Async, должна объявить один параметр. Среда выполнения надстройки использует этот параметр для предоставления доступа к объекту AsyncResult для функции обратного вызова.
Функция обратного вызова может быть анонимной или именованной функцией. Анонимную функцию удобно использовать, если код такой функции будет использован всего один раз (так как у нее нет имени, вы не сможете сослаться на нее в другой части кода). Именованные функции применяются, если необходимо многократно использовать функцию обратного вызова для нескольких асинхронных методов.
Написание функции анонимного обратного вызова
Следующая анонимная функция обратного вызова объявляет один параметр с именем result
для данных, возвращаемых клиентом. Он извлекает и записывает эти данные из свойства AsyncResult.value при возврате обратного вызова.
function (result) {
write('Selected data: ' + result.value);
}
В следующем примере показана эта анонимная функция обратного вызова в контексте полного асинхронного вызова метода метода Document.getSelectedDataAsync(coercionType, callback)
.
Первый аргумент coercionType , указывает для
Office.CoercionType.Text
возврата выбранных данных в виде строки текста.Второй аргумент обратного вызова — это анонимная функция, передаваемая в метод . При запуске функции она использует параметр result для доступа к свойству
value
AsyncResult
объекта . Затем отображаются данные, выбранные пользователем в документе.
Office.context.document.getSelectedDataAsync(Office.CoercionType.Text,
function (result) {
write('Selected data: ' + result.value);
}
});
// Function that writes to a div with id='message' on the page.
function write(message){
document.getElementById('message').innerText += message;
}
Вы также можете использовать параметр функции обратного вызова для доступа к другим свойствам AsyncResult
объекта . Используйте свойство AsyncResult.status, чтобы определить, успешно ли был выполнен вызов. Если вызов завершился сбоем, используйте свойство AsyncResult.error , чтобы получить доступ к объекту Error , чтобы решить, что делать.
Дополнительные сведения о методе см. в getSelectedDataAsync
статье Чтение и запись данных в активный выделенный фрагмент в документе или электронной таблице.
Написание именованной функции обратного вызова
Кроме того, можно написать именованную функцию и передать ее имя в параметр обратного вызова метода Async. Здесь предыдущий пример перезаписывается для передачи функции с именем writeDataCallback
в качестве параметра обратного вызова .
Office.context.document.getSelectedDataAsync(Office.CoercionType.Text,
writeDataCallback);
// Callback to write the selected data to the add-in UI.
function writeDataCallback(result) {
write('Selected data: ' + result.value);
}
// Function that writes to a div with id='message' on the page.
function write(message){
document.getElementById('message').innerText += message;
}
Различия в том, что возвращается в AsyncResult.value
свойство
Свойства asyncContext
, status
и error
объекта возвращают одинаковые типы информации для функций обратного вызова, передаваемых во все асинхронные AsyncResult
методы. Однако то, что возвращается в AsyncResult.value
свойство, зависит от функциональности метода Async.
Например, addHandlerAsync
методы (объектов Binding, CustomXmlPart, Document, RoamingSettings и Settings ) используются для добавления функций обработчика событий. Свойство AsyncResult.value
в этих функциях обратного вызова всегда возвращает undefined, так как при добавлении обработчика событий доступ к данным или объекту не осуществляется.
С другой стороны, при вызове Document.getSelectedDataAsync
метода он возвращает данные, выбранные пользователем в документе AsyncResult.value
в качестве свойства в обратном вызове. Или при вызове метода Bindings.getAllAsync он возвращает массив всех Binding
объектов в документе.
Описание того, что возвращается AsyncResult.value
в свойство для Async
метода, см. в callback
разделе справочного раздела этого метода.
Шаблоны асинхронного программирования
Общие API в API JavaScript для Office поддерживают два типа шаблонов асинхронного программирования.
- Вложенные обратные вызовы
- Обещания
Примечание.
В текущей версии API JavaScript для Office встроенная поддержка шаблона обещаний работает только с кодом для привязок в электронных таблицах Excel и Word документах. Однако другие функции, имеющие обратные вызовы, можно поместить в собственную настраиваемую Promise
функцию возврата. Дополнительные сведения см. в статье Перенос общих API в функции promise-returning.
Асинхронное программирование с использованием вложенных функций обратного вызова
Зачастую для какой-либо задачи необходимо выполнять несколько асинхронных операций. Для этого можно вкладывать один асинхронный вызов в другой.
В следующем примере кода показано, как вложить два асинхронных вызова.
- Сначала вызывается метод Bindings.getByIdAsync для получения доступа к привязке в документе с именем "MyBinding". Объект
AsyncResult
, возвращаемый параметруresult
этого обратного вызова, предоставляет доступ к указанному объекту привязкиAsyncResult.value
из свойства . - Затем объект привязки, доступный из первого
result
параметра, используется для вызова метода Binding.getDataAsync . - Наконец, параметр обратного вызова,
result2
переданного методуBinding.getDataAsync
, используется для отображения данных в привязке.
function readData() {
Office.context.document.bindings.getByIdAsync("MyBinding", function (result) {
result.value.getDataAsync({ coercionType: 'text' }, function (result2) {
write(result2.value);
});
});
}
// Function that writes to a div with id='message' on the page.
function write(message){
document.getElementById('message').innerText += message;
}
Этот базовый вложенный шаблон обратного вызова можно использовать для всех асинхронных методов в общих API.
Асинхронное программирование с применением шаблона, предусматривающего использование обещаний для получения доступа к данным в привязках
Вместо передачи функции обратного вызова и ожидания возврата функции перед продолжением скрипта шаблон программирования promises немедленно возвращает Promise
объект, представляющий его предполагаемый результат. Однако в отличие от реального синхронного программирования выполнение обещанного результата фактически откладывается до тех пор, пока среда выполнения надстроек Office не завершит запрос. Если выполнить запрос не удается, используется обработчик onError.
Общие API предоставляют функцию Office.select для поддержки шаблона обещаний при работе с существующими объектами привязки. Объект promise, возвращенный функции, Office.select
поддерживает только четыре метода, напрямую доступные из объекта Binding .
Шаблон обещаний для работы с привязками принимает эту форму.
Office.select(
selectorExpression,
onError).
BindingObjectAsyncMethod;
Параметр selectorExpression принимает форму "bindings#bindingId"
, где bindingId — это имя ( id
) привязки, созданной в документе или электронной таблице (с помощью одного из методов Bindings
addFrom коллекции: addFromNamedItemAsync
, addFromPromptAsync
или addFromSelectionAsync
). В примере selectorExpressionbindings#cities
указывает, что требуется получить доступ к привязке с идентификатором "cities".
Параметр onError — это функция обработки ошибок, которая принимает один параметр типа AsyncResult
. Используется для доступа к объекту, Error
select
если функции не удается получить доступ к указанной привязке. В следующем примере показана базовая функция обработки ошибки, которую можно передать в параметр onError.
function onError(result){
const err = result.error;
write(err.name + ": " + err.message);
}
// Function that writes to a div with id='message' on the page.
function write(message){
document.getElementById('message').innerText += message;
}
Замените заполнитель BindingObjectAsyncMethod вызовом любого из четырех Binding
методов объектов, поддерживаемых объектом promise: getDataAsync
, setDataAsync
, addHandlerAsync
или removeHandlerAsync
. Вызовы этих методов не поддерживают дополнительные шаблоны promise. В этом случае необходимо использовать шаблон вложенной функции обратного вызова.
Binding
После выполнения обещания объекта его можно повторно использовать в вызове метода с цепочкой, как если бы это была привязка. В случае успешного выполнения надстройки не будет асинхронно повторять выполнение обещания.
Binding
Если обещание объекта не может быть выполнено, среда выполнения надстройки попытается снова получить доступ к объекту привязки при следующем вызове одного из его асинхронных методов.
В следующем примере функция используется select
для получения привязки id
с "cities
" из Bindings
коллекции, а затем вызывается метод addHandlerAsync для добавления обработчика событий для события dataChanged привязки.
function addBindingDataChangedEventHandler() {
Office.select("bindings#cities", function onError(){/* error handling code */}).addHandlerAsync(Office.EventType.BindingDataChanged,
function (eventArgs) {
doSomethingWithBinding(eventArgs.binding);
});
}
Важно!
Объектное Binding
обещание, возвращаемое функцией Office.select
, предоставляет доступ только к четырем Binding
методам объекта . Если необходимо получить доступ к любому из других элементов Binding
объекта, вместо этого необходимо использовать Document.bindings
методы свойства и Bindings.getByIdAsync
или Bindings.getAllAsync
для получения Binding
объекта.
Передача необязательных параметров асинхронным методам
Общий синтаксис для всех асинхронных методов соответствует этому шаблону.
asyncMethod(
requiredParameters, [
optionalParameters],
callbackFunction);
Все асинхронные методы поддерживают необязательные параметры. Они передаются в виде объекта JavaScript. Объект, содержащий необязательные параметры, представляет собой неупорядоченную коллекцию пар "ключ-значение". Можно создать объект, содержащий необязательные встроенные параметры, или путем создания options
объекта и передачи его в качестве параметра options .
Передача необязательных параметров в строке
Ниже приведен пример метода Document.setSelectedDataAsync с необязательными параметрами, определенными встроенными. Два необязательных параметра, coercionType и asyncContext, определяются как анонимный объект JavaScript.
Office.context.document.setSelectedDataAsync(
"<html><body>hello world</body></html>",
{coercionType: "html", asyncContext: 42},
function(asyncResult) {
write(asyncResult.status + " " + asyncResult.asyncContext);
}
)
// Function that writes to a div with id='message' on the page.
function write(message){
document.getElementById('message').innerText += message;
}
Передача необязательных параметров в именованном объекте
Кроме того, можно создать именованный объект, который задает необязательные параметры отдельно от вызова метода, а затем передать объект в качестве аргумента options . В следующем примере показан один из способов создания options
объекта, где parameter1
, value1
и т. д. являются заполнителями для фактических имен и значений параметров.
const options = {
parameter1: value1,
parameter2: value2,
...
parameterN: valueN
};
Когда указываются параметры ValueFormat и FilterType, код будет таким:
const options = {
valueFormat: "unformatted",
filterType: "all"
};
Вот еще один способ создания options
объекта.
const options = {};
options[parameter1] = value1;
options[parameter2] = value2;
...
options[parameterN] = valueN;
Это выглядит как в следующем примере, если используется для указания ValueFormat
параметров и FilterType
:
const options = {};
options["ValueFormat"] = "unformatted";
options["FilterType"] = "all";
В следующем примере показано, как вызвать метод путем Document.setSelectedDataAsync
указания необязательных параметров в объекте options
.
const options = {
coercionType: "html",
asyncContext: 42
};
document.setSelectedDataAsync(
"<html><body>hello world</body></html>",
options,
function(asyncResult) {
write(asyncResult.status + " " + asyncResult.asyncContext);
}
)
// Function that writes to a div with id='message' on the page.
function write(message){
document.getElementById('message').innerText += message;
}
В обоих примерах необязательных параметров параметр обратного вызова указывается как последний параметр (после встроенных необязательных параметров или после объекта аргумента options ). Кроме того, можно указать параметр обратного вызова внутри встроенного объекта JavaScript или в объекте options
. Однако параметр обратного вызова можно передать только в одном расположении: в options
объекте (встроенном или созданном извне) или в качестве последнего параметра, но не в обоих расположениях.
Перенос общих API-интерфейсов в Promise
функции возврата
Методы Common API (и API Outlook) не возвращают promises. Поэтому вы не можете использовать await для приостановки выполнения до завершения асинхронной операции. Если требуется await
поведение, заключите вызов метода в явно созданный Promise
объект .
Базовый шаблон заключается в создании асинхронного метода, который немедленно возвращает объект Promise и разрешает этот объект Promise после завершения внутреннего метода или отклоняет объект в случае сбоя метода. Ниже приведен простой пример.
function getDocumentFilePath() {
return new OfficeExtension.Promise(function (resolve, reject) {
try {
Office.context.document.getFilePropertiesAsync(function (asyncResult) {
resolve(asyncResult.value.url);
});
}
catch (error) {
reject(WordMarkdownConversion.errorHandler(error));
}
})
}
Если эту функцию необходимо ожидать, ее можно вызвать с await
помощью ключевое слово или передать в then
функцию.
Примечание.
Этот метод особенно полезен, если необходимо вызвать Общий API внутри вызова run
функции в объектной модели приложения. Пример функции, используемой getDocumentFilePath
таким образом, см. в файлеHome.js в примере Word-Add-in-JavaScript-MDConversion.
См. также
Office Add-ins