Programmation asynchrone dans des compléments Office
Importante
Cet article s’applique aux API communes, le modèle d’API JavaScript Office qui a été introduit avec Office 2013. Ces API comprennent des fonctionnalités telles qu’une interface utilisateur, des boîtes de dialogue et des paramètres du client, qui sont communes à plusieurs types d’applications Office. Les compléments Outlook utilisent uniquement les API communes, notamment le sous-ensemble d’API exposées via l’objet Boîte aux lettres .
Vous devriez utiliser les API communes uniquement pour les scénarios qui ne sont pas pris en charge par les API spécifiques de l’application. Pour savoir quand utiliser les API communes au lieu des API propres aux applications, consultez Comprendre l’API JavaScript Office.
Pourquoi l’API de Compléments Office a-t-elle recours à la programmation asynchrone ? JavaScript étant un langage monothread, si le script appelle un processus synchrone de longue durée, toute exécution de script ultérieure sera bloquée tant que ce processus ne sera pas terminé. Étant donné que certaines opérations sur les clients web Office (mais également sur les clients de bureau) peuvent bloquer l’exécution s’ils sont exécutés de manière synchrone, la plupart des API JavaScript Office sont conçues pour s’exécuter de manière asynchrone. Cela permet de s’assurer que les compléments Office sont réactifs et rapides. Vous devez donc fréquemment écrire des fonctions de rappel lorsque vous utilisez ces méthodes asynchrones.
Les noms de toutes les méthodes asynchrones dans l’API se terminent par « Async », comme les Document.getSelectedDataAsync
méthodes , Binding.getDataAsync
ou Item.loadCustomPropertiesAsync
. Lorsqu’une méthode « Async » est appelée, elle est exécutée immédiatement et toute exécution de script ultérieure peut se poursuivre normalement. La fonction de rappel facultative que vous transmettez à une méthode « Async » s’exécute dès que l’opération demandée ou les données sont prêtes. L’opération est généralement rapide, mais le retour pourrait présenter un léger retard.
Le diagramme suivant montre le flux d’exécution d’un appel à une méthode « Async » qui lit les données sélectionnées par l’utilisateur dans un document ouvert dans le serveur Word ou Excel. Au moment où l’appel « Async » est effectué, le thread d’exécution JavaScript est libre d’effectuer tout traitement supplémentaire côté client (bien qu’aucun ne soit indiqué dans le diagramme). Lorsque la méthode « Async » est retournée, le rappel reprend l’exécution sur le thread, et le complément peut accéder aux données, faire quelque chose avec elles et afficher le résultat. Le même modèle d’exécution asynchrone est valable lors de l’utilisation d’applications clientes Office sur Windows ou sur Mac.
La prise en charge de cette conception asynchrone dans les clients riches et les clients web fait partie des objectifs de conception « écriture unique-exécution multiplateforme » du modèle de développement des Compléments Office. Par exemple, vous pouvez créer un complément de contenu ou de volet Office avec une base de code unique qui s’exécutera dans Excel sur Windows et Excel sur le web.
Écrire la fonction de rappel pour une méthode « Async »
La fonction de rappel que vous passez en tant qu’argument de rappel à une méthode « Async » doit déclarer un paramètre unique que le runtime du complément utilisera pour fournir l’accès à un objet AsyncResult lors de l’exécution de la fonction de rappel. Vous pouvez écrire:
Fonction anonyme qui doit être écrite et passée directement en ligne avec l’appel à la méthode « Async » en tant que paramètre de rappel de la méthode « Async ».
Fonction nommée, en passant le nom de cette fonction comme paramètre de rappel d’une méthode « Async ».
Une fonction anonyme est utile si vous envisagez de n’utiliser son code qu’une fois : comme elle n’a pas de nom, vous ne pouvez pas y faire référence dans une autre partie du code. Une fonction nommée est utile si vous voulez réutiliser la fonction de rappel pour plusieurs méthodes « Async ».
Écrire une fonction de rappel anonyme
La fonction de rappel anonyme suivante déclare un paramètre unique nommé result
qui récupère les données de la propriété AsyncResult.value lorsque le rappel est retourné.
function (result) {
write('Selected data: ' + result.value);
}
L’exemple suivant montre comment passer cette fonction de rappel anonyme en ligne dans le contexte d’un appel de méthode « Async » complet à la Document.getSelectedDataAsync
méthode .
Le premier argument coercionType ,
Office.CoercionType.Text
, spécifie de renvoyer les données sélectionnées sous la forme d’une chaîne de texte.Le deuxième argument de rappel est la fonction anonyme passée en ligne à la méthode . Lorsque la fonction s’exécute, elle utilise le paramètre result pour accéder à la
value
propriété de l’objetAsyncResult
afin d’afficher les données sélectionnées par l’utilisateur dans le document.
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;
}
Vous pouvez également utiliser le paramètre de votre fonction de rappel pour accéder à d’autres propriétés de l’objet AsyncResult
. Utilisez la propriété AsyncResult.status pour déterminer si l’appel a réussi ou échoué. En cas d’échec, vous pouvez utiliser la propriété AsyncResult.error pour accéder à un objet Error et obtenir des informations sur l’erreur.
Pour plus d’informations sur l’utilisation de la getSelectedDataAsync
méthode , consultez Lire et écrire des données dans la sélection active dans un document ou une feuille de calcul.
Écrire une fonction de rappel nommée
Vous pouvez également écrire une fonction nommée et passer son nom au paramètre de rappel d’une méthode « Async ». Par exemple, l’exemple précédent peut être réécrit pour passer une fonction nommée writeDataCallback
en tant que paramètre callback comme suit.
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;
}
Différences dans les éléments retournés à la propriété AsyncResult.value
Les asyncContext
propriétés , status
et error
de l’objet AsyncResult
retournent les mêmes types d’informations à la fonction de rappel passées à toutes les méthodes « Async ». Toutefois, ce qui est retourné à la AsyncResult.value
propriété varie en fonction des fonctionnalités de la méthode « Async ».
Par exemple, les addHandlerAsync
méthodes (des objets Binding, CustomXmlPart, Document, RoamingSettings et Settings ) sont utilisées pour ajouter des fonctions de gestionnaire d’événements aux éléments représentés par ces objets. Vous pouvez accéder à la AsyncResult.value
propriété à partir de la fonction de rappel que vous passez à l’une addHandlerAsync
des méthodes, mais comme aucune donnée ou objet n’est accessible lorsque vous ajoutez un gestionnaire d’événements, la value
propriété retourne toujours undefined si vous tentez d’y accéder.
En revanche, si vous appelez la Document.getSelectedDataAsync
méthode, elle retourne les données sélectionnées par l’utilisateur dans le document à la AsyncResult.value
propriété dans le rappel. Ou, si vous appelez la méthode Bindings.getAllAsync , elle retourne un tableau de tous les Binding
objets du document. Et, si vous appelez la méthode Bindings.getByIdAsync , elle retourne un seul Binding
objet.
Pour obtenir une description de ce qui est retourné à la AsyncResult.value
propriété pour une Async
méthode, consultez la section « Valeur de rappel » de la rubrique de référence de cette méthode. Pour obtenir un résumé de tous les objets qui fournissent des Async
méthodes, consultez le tableau situé en bas de la rubrique objet AsyncResult .
Modèles de programmation asynchrone
L’API JavaScript Office prend en charge deux types de modèles de programmation asynchrone.
- Utilisation des rappels imbriqués
- Utilisation du modèle des promesses
La programmation asynchrone à l’aide des fonctions de rappel nécessite que vous imbriquiez fréquemment le résultat retourné d’un rappel au sein d’au moins deux rappels. Pour ce faire, vous pouvez utiliser les rappels imbriqués de toutes les méthodes « Async » de l’API.
L’utilisation des rappels imbriqués est un modèle de programmation familier pour la plupart des développeurs JavaScript, mais le code contenant des rappels fortement imbriqués peut être difficile à lire et à comprendre. En guise d’alternative aux rappels imbriqués, l’API JavaScript Office prend également en charge une implémentation du modèle de promesses.
Notes
Dans la version actuelle de l’API JavaScript Office, la prise en charge intégrée du modèle promesses fonctionne uniquement avec le code pour les liaisons dans les feuilles de calcul Excel et les documents Word. Toutefois, vous pouvez encapsuler d’autres fonctions qui ont des rappels à l’intérieur de votre propre fonction de retour de promesse personnalisée. Pour plus d’informations, consultez Wrapper les API courantes dans les fonctions de retour de promesses.
Programmation asynchrone utilisant des fonctions de rappel imbriquées
Vous devez fréquemment effectuer au moins deux opérations asynchrones pour réaliser une tâche. Pour ce faire, vous pouvez imbriquer un appel « Async » dans un autre.
L’exemple de code suivant imbrique deux appels asynchrones.
- D’abord, la méthode Bindings.getByIdAsync est appelée pour accéder à une liaison dans le document nommé « MyBinding ». L’objet
AsyncResult
retourné auresult
paramètre de ce rappel fournit l’accès à l’objet de liaison spécifié à partir de laAsyncResult.value
propriété . - Ensuite, l’objet de liaison accessible à partir du premier
result
paramètre est utilisé pour appeler la méthode Binding.getDataAsync . - Enfin, le
result2
paramètre du rappel passé à laBinding.getDataAsync
méthode est utilisé pour afficher les données dans la liaison.
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;
}
Ce modèle de rappel imbriqué de base peut être utilisé pour toutes les méthodes asynchrones dans l’API JavaScript Office.
Les sections suivantes montrent comment utiliser des fonctions anonymes ou nommées pour des rappels imbriqués dans des méthodes asynchrones.
Utiliser des fonctions anonymes pour les rappels imbriqués
Dans l’exemple suivant, deux fonctions anonymes sont déclarées inline et passées aux getByIdAsync
méthodes et getDataAsync
en tant que rappels imbriqués. Comme les fonctions sont très simples, l’objet de l’implémentation est évident.
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;
}
Utiliser des fonctions nommées pour les rappels imbriqués
Dans des implémentations complexes, il peut être utile d’utiliser des fonctions nommées pour garantir une meilleure lisibilité, simplicité de gestion et possibilité de réutilisation du code. Dans l’exemple suivant, les deux fonctions anonymes de l’exemple de la section précédente ont été réécrites en tant que fonctions nommées deleteAllData
et showResult
. Ces fonctions nommées sont ensuite passées dans les getByIdAsync
méthodes et deleteAllDataValuesAsync
en tant que rappels par nom.
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;
}
Programmation asynchrone en utilisant le modèle des promesses pour accéder aux données des liaisons
Plutôt que de transmettre une fonction de rappel et d’attendre le renvoi de la fonction pour poursuivre l’exécution, le motif de programmation des promesses renvoie immédiatement un objet de promesse qui représente le résultat souhaité. Toutefois, contrairement à la vraie programmation synchrone, en arrière-plan, la concrétisation du résultat prévu est en fait différée jusqu’à ce que l’environnement d’exécution des compléments Office puisse réaliser la demande. Un gestionnaire onError est fourni pour couvrir les cas où la demande ne peut pas être remplie.
L’API JavaScript Office fournit la fonction Office.select pour prendre en charge le modèle de promesses pour l’utilisation d’objets de liaison existants. L’objet promise retourné à la Office.select
fonction prend uniquement en charge les quatre méthodes auxquelles vous pouvez accéder directement à partir de l’objet Binding : getDataAsync, setDataAsync, addHandlerAsync et removeHandlerAsync.
Le modèle promesses pour l’utilisation des liaisons prend cette forme.
Office.select(selectorExpression, onError).BindingObjectAsyncMethod
Le paramètre selectorExpression prend la forme "bindings#bindingId"
, où bindingId est le nom ( id
) d’une liaison que vous avez créée précédemment dans le document ou la feuille de calcul (à l’aide de l’une des méthodes « addFrom » de la Bindings
collection : addFromNamedItemAsync
, addFromPromptAsync
ou addFromSelectionAsync
). Par exemple, l’expression bindings#cities
de sélecteur spécifie que vous souhaitez accéder à la liaison avec l’ID « cities ».
Le paramètre onError est une fonction de gestion des erreurs qui accepte un seul paramètre de type AsyncResult
qui peut être utilisé pour accéder à un Error
objet, si la select
fonction ne parvient pas à accéder à la liaison spécifiée. L’exemple suivant montre une fonction de gestion des erreurs de base pouvant être passée au paramètre 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;
}
Remplacez l’espace réservé BindingObjectAsyncMethod par un appel à l’une des quatre Binding
méthodes d’objet prises en charge par l’objet promise : getDataAsync
, setDataAsync
, addHandlerAsync
ou removeHandlerAsync
. Les appels à ces méthodes ne prennent pas en charge les promesses supplémentaires. Vous devez les appeler à l’aide du modèle de fonction de rappel imbriquée.
Une fois qu’une promesse d’objet Binding
est remplie, elle peut être réutilisée dans l’appel de méthode chaînée comme s’il s’agissait d’une liaison (le runtime du complément ne réessaye pas de remplir la promesse de manière asynchrone). Si la Binding
promesse d’objet ne peut pas être remplie, le runtime du complément réessayera d’accéder à l’objet de liaison la prochaine fois qu’une de ses méthodes asynchrones sera appelée.
L’exemple de code suivant utilise la select
fonction pour récupérer une liaison avec le id
«cities
» de la Bindings
collection, puis appelle la méthode addHandlerAsync pour ajouter un gestionnaire d’événements pour l’événement dataChanged de la liaison.
function addBindingDataChangedEventHandler() {
Office.select("bindings#cities", function onError(){/* error handling code */}).addHandlerAsync(Office.EventType.BindingDataChanged,
function (eventArgs) {
doSomethingWithBinding(eventArgs.binding);
});
}
Importante
La Binding
promesse d’objet retournée par la Office.select
fonction fournit uniquement l’accès aux quatre méthodes de l’objet Binding
. Si vous avez besoin d’accéder à l’un des autres membres de l’objet Binding
, vous devez utiliser la Document.bindings
propriété et Bindings.getByIdAsync
les méthodes ou Bindings.getAllAsync
pour récupérer l’objet Binding
. Par exemple, si vous avez besoin d’accéder à l’une des propriétés de l’objet Binding
(propriétés document
, id
ou type
), ou si vous avez besoin d’accéder aux propriétés des objets MatrixBinding ou TableBinding , vous devez utiliser les getByIdAsync
méthodes ou getAllAsync
pour récupérer un Binding
objet.
Passer des paramètres facultatifs aux méthodes asynchrones
La syntaxe commune de toutes les méthodes « Async » suit ce modèle.
AsyncMethod(
RequiredParameters, [
OptionalParameters],
CallbackFunction);
Toutes les méthodes asynchrones prennent en charge les paramètres facultatifs, qui sont transmis en tant qu’objet JavaScript qui contient un ou plusieurs paramètres facultatifs. L’objet contenant les paramètres facultatifs est une collection non triée de paires clé-valeur avec le caractère « : » séparant la clé et la valeur. Chaque paire dans l’objet est séparée par une virgule, et l’ensemble complet de paires est placé entre accolades. La clé est le nom du paramètre, et la valeur est la valeur à passer pour ce paramètre.
Vous pouvez créer l’objet qui contient des paramètres facultatifs inline, ou en créant un options
objet et en le transmettant en tant que paramètre options .
Passer des paramètres facultatifs inline
Par exemple, la syntaxe pour appeler la méthode Document.setSelectedDataAsync avec des paramètres facultatifs incorporés se présente comme ceci :
Office.context.document.setSelectedDataAsync(data, {coercionType: 'coercionType', asyncContext: 'asyncContext'},callback);
Dans cette forme de syntaxe d’appel, les deux paramètres facultatifs, coercionType et asyncContext, sont définis comme un objet JavaScript anonyme placé entre accolades.
L’exemple suivant montre comment appeler la Document.setSelectedDataAsync
méthode en spécifiant des paramètres facultatifs inline.
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;
}
Notes
Vous pouvez spécifier des paramètres facultatifs dans n’importe quel ordre dans l’objet paramètre tant que leurs noms sont spécifiés correctement.
Passer des paramètres facultatifs dans un objet options
Vous pouvez également créer un objet nommé options
qui spécifie les paramètres facultatifs séparément de l’appel de méthode, puis passer l’objet options
comme argument options .
L’exemple suivant montre une façon de créer l’objet options
, où parameter1
, value1
, et ainsi de suite, sont des espaces réservés pour les noms et valeurs de paramètres réels.
const options = {
parameter1: value1,
parameter2: value2,
...
parameterN: valueN
};
Ce qui ressemble à l’exemple suivant lors de la spécification des paramètres ValueFormat et FilterType.
const options = {
valueFormat: "unformatted",
filterType: "all"
};
Voici une autre façon de créer l’objet options
.
const options = {};
options[parameter1] = value1;
options[parameter2] = value2;
...
options[parameterN] = valueN;
Qui ressemble à l’exemple suivant lorsqu’il est utilisé pour spécifier les ValueFormat
paramètres et FilterType
:
const options = {};
options["ValueFormat"] = "unformatted";
options["FilterType"] = "all";
Notes
Lorsque vous utilisez l’une ou l’autre méthode de création de l’objet options
, vous pouvez spécifier des paramètres facultatifs dans n’importe quel ordre tant que leurs noms sont spécifiés correctement.
L’exemple suivant montre comment appeler la Document.setSelectedDataAsync
méthode en spécifiant des paramètres facultatifs dans un options
objet .
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;
}
Dans les deux exemples de paramètres facultatifs, le paramètre de rappel est spécifié comme dernier paramètre (suivant les paramètres facultatifs inline ou suivant l’objet d’argument options ). Vous pouvez également spécifier le paramètre de rappel à l’intérieur de l’objet JavaScript inline ou dans l’objet options
. Toutefois, vous ne pouvez passer le paramètre de rappel qu’à un seul emplacement : soit dans l’objet options
(inline ou créé en externe), soit en tant que dernier paramètre, mais pas les deux.
Encapsuler les API courantes dans les fonctions de retour de promesses
Les méthodes d’API commune (et d’API Outlook) ne retournent pas de promesses. Par conséquent, vous ne pouvez pas utiliser await pour suspendre l’exécution tant que l’opération asynchrone n’est pas terminée. Si vous avez besoin d’un await
comportement, vous pouvez encapsuler l’appel de méthode dans une promesse explicitement créée.
Le modèle de base consiste à créer une méthode asynchrone qui retourne immédiatement un objet Promise et résout cet objet Promise lorsque la méthode interne se termine, ou rejette l’objet en cas d’échec de la méthode. Voici un exemple simple.
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));
}
})
}
Lorsque cette fonction doit être attendue, elle peut être appelée avec le await
mot clé ou passée à une then
fonction.
Notes
Cette technique est particulièrement utile lorsque vous devez appeler une API commune à l’intérieur d’un appel de la run
fonction dans un modèle objet spécifique à l’application. Pour obtenir un exemple de la getDocumentFilePath
fonction utilisée de cette façon, consultez le fichier Home.js dans l’exemple Word-Add-in-JavaScript-MDConversion.
Voici un exemple utilisant 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);
}
});
}
});
});
}