Programação assíncrona em Suplementos do Office
Importante
Este artigo se aplica às APIs Comuns, o modelo de API JavaScript do Office que foi introduzido com o Office 2013. Essas APIs incluem recursos como interface de usuário, caixas de diálogo e configurações de cliente, que são comuns entre vários tipos de aplicativos do Office. Os suplementos do Outlook usam exclusivamente APIs comuns, especialmente o subconjunto de APIs expostos por meio do objetoCaixa de Correio.
Você só deve usar APIs comuns para cenários que não têm suporte por APIs específicas do aplicativo. Para saber quando usar APIs comuns em vez de APIs específicas do aplicativo, confira Entendendo a API de JavaScript do Office.
Por que a API de Suplementos do Office usa a programação assíncrona? Como o JavaScript é uma linguagem de thread único, se o script invocar um processo síncrono demorado, todas as execuções subsequentes do script serão bloqueadas até que o processo seja concluído. Como determinadas operações contra clientes Web do Office (mas também clientes de área de trabalho) podem bloquear a execução se forem executadas de forma síncrona, a maioria das APIs JavaScript do Office são projetadas para serem executadas de forma assíncrona. Isso garante que os suplementos do Office sejam responsivos e rápidos. Em geral, isso também requer que você escreva funções de retorno de chamada ao trabalhar com esses métodos assíncronos.
Os nomes de todos os métodos assíncronos na API terminam com "Async", como os Document.getSelectedDataAsync
métodos , Binding.getDataAsync
ou Item.loadCustomPropertiesAsync
. Quando um método "Async" é chamado, ele é executado imediatamente e qualquer execução subsequente do script poderá continuar. A função de retorno de chamada opcional que você passar para um método de "Async" é executada assim que os dados ou a operação solicitada está pronta. Isso geralmente ocorre imediatamente, mas pode haver um pequeno atraso antes de retornar.
O diagrama a seguir mostra o fluxo de execução de uma chamada para um método "Assíncrono" que lê os dados que o usuário selecionou em um documento aberto no Word ou Excel baseado no servidor. No ponto em que a chamada "Async" é feita, o thread de execução javaScript é gratuito para executar qualquer processamento adicional do lado do cliente (embora nenhum seja mostrado no diagrama). Quando o método "Async" retorna, o retorno de chamada retoma a execução no thread e o suplemento pode acessar dados, fazer algo com ele e exibir o resultado. O mesmo padrão de execução assíncrono contém ao trabalhar com aplicativos cliente do Office no Windows ou no Mac.
O suporte a esse design assíncrono em clientes Web e avançados faz parte das metas de design "gravar plataforma cruzada já executada" do modelo de desenvolvimento de Suplementos do Office. Por exemplo, você pode criar um suplemento de conteúdo ou painel de tarefas com uma única base de código que será executada no Excel no Windows e Excel na Web.
Gravar a função de retorno de chamada para um método "Assíncrono"
A função de retorno de chamada que você passa como o argumento de retorno de chamada para um método "Async" deve declarar um único parâmetro que o runtime de suplemento usará para fornecer acesso a um objeto AsyncResult quando a função de retorno de chamada for executada. Você pode gravar:
Uma função anônima que deve ser escrita e passada diretamente de acordo com a chamada para o método "Async" como o parâmetro de retorno de chamada do método "Async".
Uma função nomeada, passando o nome dessa função como o parâmetro de retorno de chamada de um método "Async".
Uma função anônima é útil se você só for usar seu código uma vez - porque ele não possui um nome, você não pode referenciá-la em outra parte do seu código. Uma função nomeada é útil se você quiser reutilizar a função retorno de chamada para mais de um método "Async".
Gravar uma função de retorno de chamada anônima
A função de retorno de chamada anônima a seguir declara um único parâmetro chamado result
que recupera dados da propriedade AsyncResult.value quando o retorno de chamada retorna.
function (result) {
write('Selected data: ' + result.value);
}
O exemplo a seguir mostra como passar essa função de retorno de chamada anônima na linha no contexto de uma chamada completa do método "Async" para o Document.getSelectedDataAsync
método.
O primeiro argumento coercionType ,
Office.CoercionType.Text
, especifica para retornar os dados selecionados como uma cadeia de texto.O segundo argumento de retorno de chamada é a função anônima passada na linha para o método. Quando a função é executada, ela usa o parâmetro de resultado para acessar a
value
propriedade doAsyncResult
objeto para exibir os dados selecionados pelo usuário no documento.
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;
}
Você também pode usar o parâmetro da função de retorno de chamada para acessar outras propriedades do AsyncResult
objeto. Use a propriedade AsyncResult.status para determinar se a chamada teve êxito ou falhou. Se sua chamada falhar, você pode usar a propriedade AsyncResult.error para acessar um objeto Error para informações sobre o erro.
Para obter mais informações sobre como usar o getSelectedDataAsync
método, consulte Ler e gravar dados na seleção ativa em um documento ou planilha.
Gravar uma função de retorno de chamada nomeada
Como alternativa, você pode escrever uma função nomeada e passar seu nome para o parâmetro de retorno de chamada de um método "Async". Por exemplo, o exemplo anterior pode ser reescrito para transmitir uma função chamada writeDataCallback
como o parâmetro callback assim.
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;
}
Diferenças entre o que é retornado para a propriedade AsyncResult.value
As asyncContext
propriedades , status
e error
do AsyncResult
objeto retornam os mesmos tipos de informações para a função de retorno de chamada passada para todos os métodos "Async". No entanto, o que é retornado à AsyncResult.value
propriedade varia dependendo da funcionalidade do método "Assíncrono".
Por exemplo, os addHandlerAsync
métodos (dos objetos Binding, CustomXmlPart, Document, RoamingSettings e Settings) são usados para adicionar funções de manipulador de eventos aos itens representados por esses objetos. Você pode acessar a AsyncResult.value
propriedade a partir da função de retorno de chamada que você passa para qualquer um dos addHandlerAsync
métodos, mas como nenhum dado ou objeto está sendo acessado quando você adiciona um manipulador de eventos, a value
propriedade sempre retorna indefinida se você tentar acessá-la.
Por outro lado, se você chamar o Document.getSelectedDataAsync
método, ele retornará os dados que o usuário selecionou no documento para a AsyncResult.value
propriedade no retorno de chamada. Ou, se você chamar o método Bindings.getAllAsync , ele retornará uma matriz de todos os Binding
objetos no documento. E, se você chamar o método Bindings.getByIdAsync , ele retornará um único Binding
objeto.
Para obter uma descrição do que é retornado à AsyncResult.value
propriedade para um Async
método, consulte a seção "Valor de retorno de chamada" do tópico de referência desse método. Para obter um resumo de todos os objetos que fornecem Async
métodos, consulte a tabela na parte inferior do tópico de objeto AsyncResult .
Padrões de programação assíncrona
A API JavaScript do Office dá suporte a dois tipos de padrões de programação assíncronos.
- Usando retornos de chamada aninhados
- Usando o padrão de promessas
A programação assíncrona com funções de retorno de chamada frequentemente exigem que você aninhe o resultado retornado de um retorno de chamada dentro de dois ou mais retornos de chamada. Se você precisar fazer isso, é possível usar retornos de chamada aninhados de todos os métodos "Async" da API.
Usar retornos de chamada aninhados é um padrão de programação familiar para a maioria dos desenvolvedores de JavaScript, mas códigos com retornos de chamada profundamente aninhados podem ser difíceis de ler e entender. Como alternativa aos retornos de chamada aninhados, a API JavaScript do Office também dá suporte a uma implementação do padrão de promessas.
Observação
Na versão atual da API JavaScript do Office, o suporte interno para o padrão de promessas funciona apenas com código para associações em planilhas do Excel e documentos Word. No entanto, você pode envolver outras funções que têm retornos de chamada dentro de sua própria função de retorno de promessa personalizada. Para obter mais informações, consulte Encapsular APIs comuns em funções de retorno de promessa.
Programação assíncrona usando funções aninhadas de retorno de chamada
Frequentemente, você precisa executar duas ou mais operações assíncronas para concluir uma tarefa. Para fazer isso, você pode aninhar uma chamada "Async" dentro de outra.
O exemplo de código a seguir aninha duas ou mais chamadas assíncronas.
- Primeiro, o método Bindings.getByIdAsync é chamado para acessar uma associação no documento chamado "MyBinding". O
AsyncResult
objeto retornado aoresult
parâmetro desse retorno de chamada fornece acesso ao objeto de associação especificado daAsyncResult.value
propriedade. - Em seguida, o objeto de associação acessado do primeiro
result
parâmetro é usado para chamar o método Binding.getDataAsync . - Por fim, o
result2
parâmetro do retorno de chamada passado para oBinding.getDataAsync
método é usado para exibir os dados na associação.
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;
}
Esse padrão de retorno de chamada aninhado básico pode ser usado para todos os métodos assíncronos na API JavaScript do Office.
As seções a seguir mostram como usar funções anônimas ou nomeadas para retornos de chamada aninhados em métodos assíncronos.
Usar funções anônimas para retornos de chamada aninhados
No exemplo a seguir, duas funções anônimas são declaradas embutidas e passadas para os getByIdAsync
métodos e getDataAsync
como retornos de chamada aninhados. Como as funções são simples e embutidas, a intenção da implementação fica imediatamente clara.
Office.context.document.bindings.getByIdAsync('myBinding', function (bindingResult) {
bindingResult.value.getDataAsync(function (getResult) {
if (getResult.status == Office.AsyncResultStatus.Failed) {
write('Action failed. Error: ' + asyncResult.error.message);
} else {
write('Data has been read successfully.');
}
});
});
// Function that writes to a div with id='message' on the page.
function write(message){
document.getElementById('message').innerText += message;
}
Usar funções nomeadas para retornos de chamada aninhados
Em implementações complexas, pode ser útil usar funções nomeadas para facilitar a leitura, manutenção e reutilização do seu código. No exemplo a seguir, as duas funções anônimas do exemplo na seção anterior foram reescritas como funções nomeadas deleteAllData
e showResult
. Essas funções nomeadas são então passadas para os getByIdAsync
métodos e deleteAllDataValuesAsync
como retornos de chamada pelo nome.
Office.context.document.bindings.getByIdAsync('myBinding', deleteAllData);
function deleteAllData(asyncResult) {
asyncResult.value.deleteAllDataValuesAsync(showResult);
}
function showResult(asyncResult) {
if (asyncResult.status == Office.AsyncResultStatus.Failed) {
write('Action failed. Error: ' + asyncResult.error.message);
} else {
write('Data has been deleted successfully.');
}
}
// Function that writes to a div with id='message' on the page.
function write(message){
document.getElementById('message').innerText += message;
}
Programação assíncrona usando o padrão de promessas para acessar dados em associações
Em vez de transmitir a função de retorno de chamada e aguardar até que a função retorne antes da continuação da execução, o padrão de programação de promessas retorna imediatamente retorna um objeto de promessa que representa o resultado desejado. No entanto, ao contrário da verdadeira programação síncrona, nos bastidores o cumprimento do resultado prometido é, na verdade, adiado até que o ambiente de tempo de execução dos Suplementos do Office possa concluir a solicitação. Um manipulador onError é fornecido para atender a situações em que a solicitação não pode ser cumprida.
A API JavaScript do Office fornece a função Office.select para dar suporte ao padrão de promessas para trabalhar com objetos de associação existentes. O objeto promise retornado à Office.select
função dá suporte apenas aos quatro métodos que você pode acessar diretamente do objeto Binding : getDataAsync, setDataAsync, addHandlerAsync e removeHandlerAsync.
O padrão de promessas para trabalhar com associações toma esse formulário.
Office.select(selectorExpression, onError).BindingObjectAsyncMethod
O parâmetro selectorExpression usa o formulário "bindings#bindingId"
, em que bindingId é o nome ( id
) de uma associação que você criou anteriormente no documento ou planilha (usando um dos métodos "addFrom" da Bindings
coleção: addFromNamedItemAsync
, addFromPromptAsync
ou addFromSelectionAsync
). Por exemplo, a expressão bindings#cities
seletor especifica que você deseja acessar a associação com uma id de "cidades".
O parâmetro onError é uma função de tratamento de erro que usa um único parâmetro de tipo AsyncResult
que pode ser usado para acessar um Error
objeto, se a select
função não acessar a associação especificada. O exemplo a seguir mostra uma função de manipulador de erro básica que pode ser transmitida para o parâmetro 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;
}
Substitua o espaço reservado BindingObjectAsyncMethod por uma chamada para qualquer um dos quatro Binding
métodos de objeto compatíveis com o objeto promise: getDataAsync
, setDataAsync
, addHandlerAsync
ou removeHandlerAsync
. As chamadas para esses métodos não oferecem suporte a promessas adicionais. Você deve chamá-los usando o padrão de função de retorno de chamada aninhado.
Depois que uma Binding
promessa de objeto for cumprida, ela pode ser reutilizado na chamada de método encadeado como se fosse uma associação (o runtime de suplemento não tentará assíncronamente cumprir a promessa). Se a Binding
promessa do objeto não puder ser cumprida, o runtime de suplemento tentará novamente acessar o objeto de associação na próxima vez que um de seus métodos assíncronos for invocado.
O exemplo de código a seguir usa a select
função para recuperar uma associação com o id
"cities
" da Bindings
coleção e, em seguida, chama o método addHandlerAsync para adicionar um manipulador de eventos para o evento dataChanged da associação.
function addBindingDataChangedEventHandler() {
Office.select("bindings#cities", function onError(){/* error handling code */}).addHandlerAsync(Office.EventType.BindingDataChanged,
function (eventArgs) {
doSomethingWithBinding(eventArgs.binding);
});
}
Importante
A Binding
promessa de objeto retornada pela Office.select
função fornece acesso apenas aos quatro métodos do Binding
objeto. Se você precisar acessar qualquer um dos outros membros do Binding
objeto, em vez disso, você deve usar a Document.bindings
propriedade e Bindings.getByIdAsync
ou Bindings.getAllAsync
os métodos para recuperar o Binding
objeto. Por exemplo, se você precisar acessar qualquer uma das Binding
propriedades do objeto (as document
id
, ou type
propriedades) ou precisar acessar as propriedades dos objetos MatrixBinding ou TableBinding, você deve usar os getByIdAsync
métodos ou getAllAsync
para recuperar um Binding
objeto.
Passar parâmetros opcionais para métodos assíncronos
A sintaxe comum para todos os métodos "Assíncronos" segue esse padrão.
AsyncMethod(
Parameters obrigatórios, [
OpcionalParameters],
CallbackFunction);
Todos os métodos assíncronos dão suporte a parâmetros opcionais, que são passados como um objeto JavaScript que contém um ou mais parâmetros opcionais. O objeto que contém os parâmetros opcionais é uma coleção não ordenada de pares chave-valor com o caractere ":" separando a chave e o valor. Cada par do objeto é separado por vírgula e o conjunto completo de pares é incluído entre chaves. A chave é o nome do parâmetro e o valor é o valor a ser transmitido para esse parâmetro.
Você pode criar o objeto que contém parâmetros opcionais embutidos ou criando um options
objeto e passando-o como o parâmetro de opções .
Passar parâmetros opcionais embutidos
Por exemplo, a sintaxe para chamar o método Document.setSelectedDataAsync com parâmetros opcionais embutidos tem esta aparência:
Office.context.document.setSelectedDataAsync(data, {coercionType: 'coercionType', asyncContext: 'asyncContext'},callback);
Nesta forma da sintaxe de chamada, os dois parâmetros opcionais, coercionType e asyncContext, são definidos como um objeto JavaScript anônimo embutido em chaves.
O exemplo a seguir mostra como chamar o Document.setSelectedDataAsync
método especificando parâmetros opcionais embutidos.
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;
}
Observação
Você pode especificar parâmetros opcionais em qualquer ordem no objeto de parâmetro, desde que seus nomes sejam especificados corretamente.
Passar parâmetros opcionais em um objeto de opções
Como alternativa, você pode criar um objeto chamado options
que especifica os parâmetros opcionais separadamente da chamada do método e, em seguida, passar o options
objeto como o argumento de opções .
O exemplo a seguir mostra uma maneira de criar o options
objeto, em parameter1
que , value1
e assim por diante, são espaços reservados para os nomes e valores de parâmetro reais.
const options = {
parameter1: value1,
parameter2: value2,
...
parameterN: valueN
};
Que é semelhante ao exemplo a seguir quando usado para especificar os parâmetros ValueFormat e FilterType.
const options = {
valueFormat: "unformatted",
filterType: "all"
};
Aqui está outra maneira de criar o options
objeto.
const options = {};
options[parameter1] = value1;
options[parameter2] = value2;
...
options[parameterN] = valueN;
Que se parece com o exemplo a seguir quando usado para especificar os ValueFormat
parâmetros e FilterType
:
const options = {};
options["ValueFormat"] = "unformatted";
options["FilterType"] = "all";
Observação
Ao usar qualquer método de criação do options
objeto, você pode especificar parâmetros opcionais em qualquer ordem, desde que seus nomes sejam especificados corretamente.
O exemplo a seguir mostra como chamar o Document.setSelectedDataAsync
método especificando parâmetros opcionais em um options
objeto.
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;
}
Em ambos os exemplos de parâmetro opcional, o parâmetro de retorno de chamada é especificado como o último parâmetro (seguindo os parâmetros opcionais embutidos ou seguindo o objeto de argumento de opções ). Como alternativa, você pode especificar o parâmetro de retorno de chamada dentro do objeto JavaScript embutido ou no options
objeto. No entanto, você pode passar o parâmetro de retorno de chamada em apenas um local: no options
objeto (embutido ou criado externamente) ou como o último parâmetro, mas não em ambos.
Envolver APIs comuns em funções de retorno de promessa
Os métodos de API Comum (e API do Outlook) não retornam Promessas. Portanto, você não pode usar o await para pausar a execução até que a operação assíncrona seja concluída. Se você precisar de await
comportamento, poderá encerrar a chamada de método em uma Promessa criada explicitamente.
O padrão básico é criar um método assíncrono que retorna um objeto Promise imediatamente e resolve o objeto Promise quando o método interno é concluído ou rejeita o objeto se o método falhar. Apresentamos um exemplo simples a seguir.
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));
}
})
}
Quando essa função precisa ser aguardada, ela pode ser chamada com o await
palavra-chave ou passada para uma then
função.
Observação
Essa técnica é especialmente útil quando você precisa chamar uma API Comum dentro de uma chamada da run
função em um modelo de objeto específico do aplicativo. Para obter um exemplo da getDocumentFilePath
função que está sendo usada dessa forma, consulte o arquivoHome.js no exemplo Word-Add-in-JavaScript-MDConversion.
A seguir está um exemplo usando TypeScript.
readDocumentFileAsync(): Promise<any> {
return new Promise((resolve, reject) => {
const chunkSize = 65536;
const self = this;
Office.context.document.getFileAsync(Office.FileType.Compressed, { sliceSize: chunkSize }, (asyncResult) => {
if (asyncResult.status === Office.AsyncResultStatus.Failed) {
reject(asyncResult.error);
} else {
// `getAllSlices` is a Promise-wrapped implementation of File.getSliceAsync.
self.getAllSlices(asyncResult.value).then(result => {
if (result.IsSuccess) {
resolve(result.Data);
} else {
reject(asyncResult.error);
}
});
}
});
});
}
Confira também
Comentários
https://aka.ms/ContentUserFeedback.
Em breve: Ao longo de 2024, eliminaremos os problemas do GitHub como o mecanismo de comentários para conteúdo e o substituiremos por um novo sistema de comentários. Para obter mais informações, consulteEnviar e exibir comentários de