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>
下面是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);
这个方法类似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.
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";
}
});
}
function cancelHandler(ev) {
if (xhrPromise != null)
xhrPromise.cancel();
}
cancle的响应操作 只需要直接调用相应promise对象的cancel()方法即可。这时候就会触发到该promise的then方法中的error处理function.
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.
aAsync()
.then(function () { return bAsync(); })
.then(function () { return cAsync(); })
.done(function () { finish(); });
不好的:
// Bad code!
aAsync().then(function () {
bAsync().then(function () {
cAsync().done(function () { finish(); });
})
});
// 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