Cómo descargar un archivo (HTML)

[ Este artículo está destinado a desarrolladores de Windows 8.x y Windows Phone 8.x que escriben aplicaciones de Windows en tiempo de ejecución. Si estás desarrollando para Windows 10, consulta la documentación más reciente

Este tema te mostrará cómo descargar un archivo.

Las aplicaciones pueden usar las API analizadas en este tema para permitir la interacción con servicios web a fin de consumir o compartir formatos multimedia populares, como fotos, música y vídeo.

Cuando se desarrolla una aplicación en JavaScript, existen dos opciones principales para solicitar archivos desde ubicaciones en Internet. Los archivos pequeños, como los activos de sitios que se recuperan con frecuencia, pueden descargarse mediante XHR para realizar la solicitud HTTP GET asincrónica. Esta función encapsula una llamada XMLHttpRequest en una promesa, el patrón de programación que habilita el comportamiento asincrónico en JavaScript.

De forma alternativa, tu aplicación puede usar Background Transfer para proporcionar una experiencia coherente al descargar multimedia más grande (vídeo y música) con una duración operativa que puede extenderse más allá de múltiples suspensiones de la aplicación o cambios en la disponibilidad de la red. Para echar un vistazo general a la transferencia en segundo plano, consulta Transferencia de datos en segundo plano.

Requisitos previos

Si necesitas ayuda general para crear una aplicación en JavaScript, consulta Crear la primera aplicación de Windows en tiempo de ejecución con JavaScript. De forma adicional, en este tema se usan promesas de JavaScript para completar las operaciones asincrónicas. Si quieres más información acerca de este patrón de programación, consulta Programación asincrónica en JavaScript con compromisos.

Para asegurarte de que la aplicación está lista para la red, debes establecer la capacidad en el archivo Package.appxmanifest del proyecto. Para obtener una definición de cada funcionalidad de red, consulta Cómo configurar funcionalidades de aislamiento de red.

Todos los ejemplos de transferencia en segundo plano de este tema se basan en la muestra de transferencia en segundo plano.

Descargar un archivo mediante XHR

Para iniciar una solicitud HTTP asincrónica básica mediante JavaScript, llama a XHR y suminístrale datos de solicitud relevantes con el parámetro Option. De forma predeterminada, la llamada a este método es un solicitud GET, así que los únicos valores necesarios suministrados a través de Option son la dirección URL y responseType. No obstante, muchos servicios web requieren autenticación y estas credenciales deberían incluirse al llamar a XHR para solicitar recursos de cualquier servicio web seguro.

Una operación GET XHR también requiere que el tipo de contenido esperado en la respuesta se especifique mediante responseType en el parámetro Option. En nuestro ejemplo, hemos solicitado un archivo .png, así que el valor de nuestro responseType es "blob". Para obtener una lista completa de tipos de contenido admitidos y ejemplos de cómo solicitarlos, consulta Cómo descargar un archivo con WinJS.xhr.


WinJS.xhr({ url: "https://www.microsoft.com/windows/Framework/images/win_logo.png", responseType: "blob" })
    .done(
        function (request) {
            var imageBlob = URL.createObjectURL(request.response);
            var imageTag = xhrDiv.appendChild(document.createElement("image"));
      imageTag.src = imageBlob;
     });

En JavaScript, cada compromiso tiene dos funciones que puedes usar para administrar los resultados de una operación asincrónica: then y done. Ambas funciones toman tres parámetros: una función que se llama al completar la descarga (es decir, cuando readyState es 4), una función que se llama cuando hay un error y una función que se llama cuando la descarga está en curso (cuando readyState es 2 o 3). Solo la función done inicia una excepción si no se controla un error. Es la función más conveniente cuando no se proporciona una función de error.

Descargar un archivo mediante transferencia en segundo plano

Al usar la transferencia en segundo plano, cada descarga existe como una DownloadOperation que expone varios métodos de control que se usan para pausar, reanudar, reiniciar o cancelar la operación. El sistema controla automáticamente los eventos de la aplicación (por ejemplo, suspensión o finalización) y los cambios en la conectividad por DownloadOperation; las descargas continuarán durante los periodos de suspensión o pausa de la aplicación y se mantendrán tras la finalización de la misma. En escenarios de red móvil, al establecer la propiedad CostPolicy, se indica si tu aplicación iniciará o continuará las descargas mientras se usa una red de uso medido para la conexión a Internet.

En los siguientes ejemplos, te explicaremos cómo crear e inicializar una descarga básica y cómo enumerar y volver a introducir operaciones persistentes de una sesión anterior de la aplicación.

Hh700370.wedge(es-es,WIN.10).gifConfigurar e iniciar una descarga de archivos mediante transferencia en segundo plano

  • El siguiente ejemplo demuestra cómo las cadenas que representan un URI y un nombre de archivo pueden usarse para crear un objeto Uri y el StorageFile que contendrá el recurso solicitado. En este ejemplo, el nuevo archivo se coloca automáticamente en una ubicación predefinida. Como alternativa, se puede usar FileSavePicker para permitir que los usuarios indiquen dónde guardar el archivo en el dispositivo. Ten en cuenta que el método load al que se llamó para reasignar las devoluciones de llamada a la DownloadOperation, si es que persiste tras la finalización de la aplicación, se encuentra en la clase DownloadOp, que definiremos más adelante en esta sección.

    function DownloadOp() {
        var download = null;
        var promise = null;
        var imageStream = null;
    
        this.start = function (uriString, fileName) {
            try {
                // Asynchronously create the file in the pictures folder.
                Windows.Storage.KnownFolders.picturesLibrary.createFileAsync(fileName, Windows.Storage.CreationCollisionOption.generateUniqueName).done(function (newFile) {
                    var uri = Windows.Foundation.Uri(uriString);
                    var downloader = new Windows.Networking.BackgroundTransfer.BackgroundDownloader();
    
                    // Create a new download operation.
                    download = downloader.createDownload(uri, newFile);
    
                    // Start the download and persist the promise to be able to cancel the download.
                    promise = download.startAsync().then(complete, error, progress);
                }, error);
            } catch (err) {
                displayException(err);
            }
        };
        // On application activation, reassign callbacks for a download
        // operation persisted from previous application state.
        this.load = function (loadedDownload) {
            try {
                download = loadedDownload;
                printLog("Found download: " + download.guid + " from previous application run.<br\>");
                promise = download.attachAsync().then(complete, error, progress);
            } catch (err) {
                displayException(err);
            }
        };
    }
    

    Observa las llamadas de método asincrónico definidas con promesas de JavaScript. En la línea 17 del ejemplo de código anterior:

    promise = download.startAsync().then(complete, error, progress);
    

    La llamada de método asincrónico está seguida por una instrucción then que indica métodos definidos por la aplicación a los que se llama cuando se devuelve un resultado de la llamada de método asincrónico. Si quieres obtener más información acerca de este patrón de programación, consulta el tema Programación asincrónica en JavaScript con promesas.

Hh700370.wedge(es-es,WIN.10).gifAgregar métodos adicionales de control de operaciones

  • Se puede aumentar el nivel de control implementando métodos DownloadOperation adicionales. Por ejemplo, si se agrega el siguiente código al ejemplo anterior, se introduce la capacidad de cancelar la descarga.

    // Cancel download.
    this.cancel = function () {
        try {
            if (promise) {
                promise.cancel();
                promise = null;
                printLog("Canceling download: " + download.guid + "<br\>");
                if (imageStream) {
                    imageStream.close();
                }
            }
            else {
                printLog("Download " + download.guid + " already canceled.<br\>");
            }
        } catch (err) {
            displayException(err);
        }
    };
    

Después de finalizada o cancelada una DownloadOperation, se liberan todos los recursos del sistema asociados a ella. Sin embargo, si tu aplicación finaliza antes de que se produzca alguno de estos eventos, se pausarán las descargas y se mantendrán en segundo plano. Los siguientes ejemplos demuestran cómo volver a introducir descargas persistentes en una nueva sesión de la aplicación.

Hh700370.wedge(es-es,WIN.10).gifEnumerar operaciones persistentes en el inicio

  1. Antes de definir la función que enumera las operaciones persistentes, necesitamos crear una matriz que contenga los objetos DownloadOperation que va a devolver:

    var downloadOps = [];
    
  2. Después definimos la función que enumera las operaciones persistidas y las almacena en nuestra matriz. Ten en cuenta que el método load al que se llamó para reasignar las devoluciones de llamada para una DownloadOperation persistente se encuentra en el ejemplo de DownloadOp que definiremos más adelante en esta sección.

    // Enumerate outstanding downloads.
    Windows.Networking.BackgroundTransfer.BackgroundDownloader.getCurrentDownloadsAsync().done(function (downloads) {
    
        for (var i = 0; i < downloads.size; i++) {
            var download = new DownloadOp();
            download.load(downloads[i]);
            downloadOps.push(download);
        }
    });
    

    Nota  

    En las aplicaciones de la Tienda de Windows Phone, las transferencias en segundo plano siguen su curso mientras la aplicación no está en primer plano. Dado que la aplicación no se está ejecutando en este escenario, no recibirá una notificación cuando la transferencia finalice. Cuando la aplicación se reanude, si consultas el progreso de la transferencia completada, verás que el estado es BackgroundTransferStatus.Running. No obstante, si anexas controladores a la transferencia como en el ejemplo de código anterior, se activará controlador de finalización de la tarea y el estado de la transferencia será actualizado.

Tiempos de espera de solicitudes

Son dos los escenarios principales relacionados con el tiempo de espera de la conexión que se deben tener en cuenta:

  • Al establecer una nueva conexión para una transferencia, la solicitud de conexión se cancelará si no se establece en cinco minutos.

  • Después de establecer una conexión, se cancelará el mensaje de solicitud HTTP que no haya recibido una respuesta transcurridos dos minutos.

En ambos escenarios, y asumiendo que hay conexión a Internet, la transferencia en segundo plano intentará realizar una solicitud hasta tres veces de manera automática. Si no se detecta una conexión a Internet, las solicitudes adicionales esperarán hasta que se establezca la conexión.

En el caso de operaciones XHR, se pueden definir valores de tiempo de espera mediante la propiedad WinJS.Promise.timeout. Para obtener más información sobre cómo se lleva a cabo esto, consulta el tema sobre cómo establecer valores de tiempo de espera con WinJS.xhr.

Guía para la depuración

Detener una sesión de depuración en Microsoft Visual Studio es comparable a cerrar la aplicación Incluso durante la depuración, la aplicación debe enumerar y, luego, reanudar, reiniciar o cancelar cualquier descarga persistente de la sesión anterior. Por ejemplo, puedes hacer que la aplicación, al iniciarse, cancele las operaciones de descarga persistente enumeradas si las operaciones anteriores no son de interés para la sesión de depuración actual.

Si existen actualizaciones del proyecto de Visual Studio (como, por ejemplo, cambios en el manifiesto de la aplicación) y la aplicación se desinstala y vuelve a implementar, GetCurrentUploadsAsync no podrá enumerar las operaciones creadas con la implementación de aplicación anterior.

Para obtener más información, consulta Depurar y probar aplicaciones de la Tienda Windows.

Cuando uses la transferencia en segundo plano durante el desarrollo, es posible que las memorias caché internas de las operaciones de transferencia activas y finalizadas dejen de estar sincronizadas. Esto puede dar como resultado que no puedas iniciar nuevas operaciones de transferencia o interactuar con operaciones existentes y objetos de BackgroundTransferGroup. En algunos casos, intentar interactuar con operaciones ya existentes puede producir un bloqueo. Este resultado puede producirse si la propiedad TransferBehavior se establece en Parallel. Este problema se produce únicamente en determinados escenarios, durante el desarrollo, y no se aplica a los usuarios finales de tu aplicación.

Cuatro escenarios en los que se usa Visual Studio pueden producir este problema:

  • Creas un proyecto nuevo con el mismo nombre de aplicación que un proyecto ya existente, pero otro lenguaje (de C++ a C#, por ejemplo).
  • Cambias la arquitectura de destino (de x86 a x64, por ejemplo) de un proyecto ya existente.
  • Cambias la cultura (de neutral a en-US, por ejemplo) en un proyecto ya existente.
  • Agregas o quitas una capacidad en el manifiesto del paquete (agregando, por ejemplo, Autenticación de empresa) en un proyecto ya existente.

El mantenimiento regular de tu aplicación, incluidas las actualizaciones de manifiesto que agregan o quitan capacidades, no causa este problema en las implementaciones de usuario final de tu aplicación.

Para evitar este problema, desinstala completamente todas las versiones de la aplicación y vuelve a implementarlas con el nuevo lenguaje, arquitectura, cultura y capacidad. Puedes hacerlo a través de la pantalla Inicio o usando PowerShell y el cmdlet Remove-AppxPackage.

Resumen y siguientes pasos

En este tema hemos revisado cómo descargar archivos mediante las API Background Transfer en JavaScript. Hemos descrito las diferencias entre las dos y resaltado cómo depende la aplicación práctica del tamaño y la duración de una descarga de archivos.

También puedes usar XHR y la transferencia en segundo plano para cargar archivos. Para ver una explicación de los conceptos básicos y ejemplos, consulta Cómo cargar un archivo.

Temas relacionados

Otros

Programación asincrónica en JavaScript con compromisos

Crear la primera aplicación de Windows en tiempo de ejecución con JavaScript

Cómo configurar las funcionalidades de red

Cómo descargar un archivo con WinJS.xhr

Cómo cargar un archivo

Referencia

HttpClient

Windows.Networking.BackgroundTransfer

WinJS.XHR

Muestras

Muestra de transferencia en segundo plano

Muestra de HttpClient