当前位置: 首页 > 工具软件 > WinJS > 使用案例 >

WinJS.Promise 初探

董品
2023-12-01

Promise基础

JavaScript is a single-threaded language. 

但是在WinJS中为了实现异步编程,所以在WinJS中使用了Promise模式Common JS Promises/A proposal 

A promise is an object. The most frequently used method on a promise object is then, which takes three parameters: a function to call when the promise completes successfully, a function to call when the promise completes with an error, and a function to provide progress information. In both the Windows Runtime and the Windows Library for JavaScript you can also use the done function, which takes the same parameters. The difference is that in the case of an error in processing, the then function returns a promise in the error state but does not throw an exception, while the donemethod throws an exception if an error function is not provided.

上面是文档中的原话,在promise中有两个最重要的方法,就是then和done,都是在promise对象执行完之后再去执行promise中的方法,三个参数,分别是对应操作执行成功后,产生错误时,执行中,这三个状态。then和done的唯一区别就是,当产生错误的时候,then方法不会抛出异常,done方法会。

myWebService.get("http://www.example.com")
    .then(function(result) { 
        return myDb.add(result); 
    })
    .then(function() {
        console.log('data successfully saved');
    }, function(error) {
        console.log('an error occurred while saving:');
        console.dir(error);
    });

上面这段代码,现实从网站获取数据,成功之后进行保存,对保存操作做了保存成功和保存出错的处理。

这段代码也说明了then操作和done操作都是可以一步步拓展下去的。

You can also group multiple promises. For example, you can use the join function run multiple asynchronous operations that call several web services and then aggregate the results.

function loadData() {
    var urls = [
        'http://www.example.com/',
        'http://www.example.org/',
        'http://www.example.net'
        ];
        
    var promises = urls.map(function (url) {
        return myWebService.get(url);
    });

    WinJS.Promise.join(promises).then(function () {
        //do the aggregation here.
    });
}
上面的代码说明了怎么使用promise完成一组操作的执行,并在执行完成之后,进行相应的处理。

Array.map(function(){})方法,是对数组中的每一个元素,都执行map方法中的参数对应的那个function()

WinJS.Promise.join(PromiseArray)方法,是将一个promiseArray放在一起,当他们全部都执行完之后,再调用then方法。

Note that you must use the then function rather than the donefunction when you join promises. The done function returns undefined rather than a promise, so that joining promises that use done is the same as joining three instances of undefined.

使用join方法的时候,添加进去的promise不可以有done方法,只能有then方法的,不然join的那些promise都会变成undefined。

下面是官方的一个例子

<div id ="result1"></div>
<div id = "result2"></div>
<div id="result3"></div>
<div id="join"></div>
<script type="text/javascript">
    var promiseArray = [];
    var index = 0;

    promiseArray[0] = WinJS.Promise.timeout(2000).
        then(function () {
            document.getElementById("result1").textContent = "First promise is fullfilled after 2 seconds";
    });

    promiseArray[1] = WinJS.Promise.timeout(3000).
        then(function () {
             document.getElementById("result2").textContent = "Second promise is fullfilled after 3 seconds";
     });

    promiseArray[2] = WinJS.Promise.timeout(4000).
        then(function () {
            document.getElementById("result3").textContent = "Third promise is fullfilled after 4 seconds";
    });
        
    WinJS.Promise.join(promiseArray).
        done(function () {
            var endDiv = document.getElementById("join");
             endDiv.style.backgroundColor = "green";
            endDiv.textContent = "Calling join() makes sure that this function will not be called until all the promises have been completed";
     });
</script>

WinJS.xhr Demo

下面是xhr使用的一个demo

<div>
<input id="inUrl" />
</div>
<div id="divResult">Result</div>
然后定义input的响应

WinJS.Utilities.ready(function () {
    var input = document.getElementById("inUrl");
    input.addEventListener("change", changeHandler);
  }, false);

the  WinJS.Utilities.ready  function. It's called immediately after the  DOMContentLoaded  event, which fires after the page has been parsed but before all the resources are loaded.

这个方法类似ios中的viewDidLoad方法,界面dom加载完成,但资源还未加载的时候会调用ready方法。

在ready中,为input注册了监听器。下面是监听器的代码

function changeHandler(e) {
    var input = e.target;
    var resDiv = document.getElementById("divResult");

    WinJS.xhr({url: e.target.value}).then(
        function fulfilled (result) {
            if (result.status === 200) {
                resDiv.style.backgroundColor = "lightGreen";
                resDiv.innerText = "Success";
            }
        }, 
        function error(e) {
            resDiv.style.backgroundColor = "red";

            if (e.message != undefined) {  // If the URL is really malformed or blank.
            resDiv.innerText = e.message;
            }
            else if (e.statusText != undefined) { // If an XmlHttpRequest is made.
                resDiv.innerText = e.statusText;
            }
            else {    
                resDiv.innerText = "Error";
            }
    });
}
promise还有onerror的hander,所有promise的错误,都会触发它,是一个一般的触发器

function activatedHandler() {
    var input = document.getElementById("inUrl");
    input.addEventListener("change", changeHandler);
    WinJS.Promise.onerror = errorHandler
}
function errorhandler(event) {
        var ex = event.detail.exception;
        var promise = event.detail.promise;
    }

The error event provides general error information, such as the exception, the promise in which it occurred, and the current state of the promise (which is always error). But it probably doesn't provide all the information you need to handle the error gracefully. Still, it can provide useful information about errors that you don't explicitly handle elsewhere in your code.

cancel Promise

var xhrDiv = document.getElementById("xhrDiv");
var startBtn = document.getElementById("startBtn");
var cancelBtn = document.getElementById("cancelBtn");
var xhrPromise = null;

WinJS.Application.addEventListener("activated", activateHandler);

function activateHandler(ev) {
    startBtn.addEventListener("click", startHandler);
    cancelBtn.addEventListener("click", cancelHandler);
}

function startHandler() {
    xhrDiv.textContent = "";
    xhrDiv.style.backgroundColor = "#000000";
    xhrPromise = WinJS.xhr({ url: "<your choice of URL>" })
        .then(function complete(result) {
            xhrDiv.textContent = "Downloaded the page";
            xhrDiv.style.backgroundColor = "#00FF00";
        }, 
        function error(result) {
            if (result.name == "Canceled") {
                xhrDiv.textContent = result.message;
                xhrDiv.style.backgroundColor = "#FF0000";
            }
            else {
                xhrDiv.textContent = "other error";
                xhrDiv.style.backgroundColor = "#FF00FF";
            } 
        });
}

在开始按钮的action中,进行一个xhr操作,并且需要有错误时的响应,且在响应中,需要对cancel操作进行识别
如果是cancel的promise 那么error的参数的name属性是Canceled,如果是其他的错误,那么这个参数name属性是 XmlHttpRequest
function cancelHandler(ev) {
    if (xhrPromise != null)
        xhrPromise.cancel();
}
cancle的响应操作 只需要直接调用相应promise对象的cancel()方法即可。这时候就会触发到该promise的then方法中的error处理function.

then() 与 done() 的区别

  • You can chain multiple then functions, because then returns a promise. You cannot chain more than one donemethod, because it returns undefined.

  • If you do not provide an error handler to done and the operation has an error, an exception is thrown to the event loop. This means that you cannot catch the exception inside a try/catch block, but you can catch it inwindow.onerror. If you do not provide an error handler to then and the operation has an error, it does not throw an exception but rather returns a promise in the error state.

  • You should prefer flat promise chains to nested ones. The formatting of promise chains makes them easier to read, and it's much easier to deal with errors in promise chains.

对于第三点,也就是多个promise的组织形式,线性的组织方式好过于网状的
好的:
aAsync()
    .then(function () { return bAsync(); })
    .then(function () { return cAsync(); })
    .done(function () { finish(); });
不好的:
// Bad code!
aAsync().then(function () {
    bAsync().then(function () {
            cAsync().done(function () { finish(); });
    })
});

chaining promise demo

The following example shows how to download a web page asynchronously to a file by using the startAsync function with progress and error handlers.

 // Assign the URI to download from.
var uriExample = new Windows.Foundation.Uri("http://www.microsoft.com");

// Get the folder for temporary files.
var tempFolder = Windows.Storage.ApplicationData.current.temporaryFolder;

// Create the temp file asynchronously.
tempFolder.createFileAsync("tempfile.txt")
   .then(function (tempFile) {
       // The createFileAsync call succeeded, so start the download operation.
       var downloader = new Windows.Networking.BackgroundTransfer.BackgroundDownloader();
       var transfer = downloader.createDownload(uriExample, tempFile);
        return transfer.startAsync(); 
   })
   .then(
       //Define the function to use when the download completes successfully
       function (result) {
           console.log("File download complete.");
       },
       // Define the error handling function.
       function (error) {
           console.log("File download failed.");
       },
       // Define the progress handling function.
       function (progress) {
           console.log("Bytes retrieved: " + progress.progress.bytesReceived);
       });
创建文件、下载输入到文件中、下载完成。这三个动作是一个promise chain

 类似资料: