Windows Runtime (WinRT) for JavaScript学习笔记。
从wwahost.exe加载的WebApp可以访问WinRT的API。从Edge Webview不仅可以加载远程的Web,也可以加载本地的内容,并且从MSApp访问流(stream)块(blob)接口以及用于JS对象和WinRT对象之间转化的接口。
文档中列举了一些JS可以访问的WinRT的API接口的根级命名空间。
Using the Windows Runtime in JavaScript
JS不仅可以访问Windows中自带的WinRT接口,也可以访问自定义WinRT组件的接口。有一些命名上的差比需要识别:
- 命名空间在JS中以大写开头,比如:
Windows.Deployment.PackageInfo;
- 类成员,包括方法与部属,或者结构以及枚举的成员,都是驼峰(camel case)格式命名:
Deployment.PackageInfo.createPackage();
- 事件采用全小写命名:
dataTransferManager.ontargetapplicationchosen;
Considerations when Using the Windows Runtime API
WinRT类型在JS中的表示需要注意的地方:
- 字符串:未初始化的字符串传给WinRT的时候,其值是“undefined”;null字符串传递给WinRT的时候,其值为“null”。为了避免意外,将字符串传递给WinRT的时候,最好将其初始化为""。
- 接口:无法用JS实现一个WinRT的接口类型
- 数组:WinRT的数组无法改变大小,所以JS的数组大小相关的操作不能用于WinRT数组
- 数组:如果传递一个JS的数组给WinRT,这个数组会被拷贝。WinRT无法修改数组内容之后返还此数组。但是你可以使用类型数组,比如Int32Array Object这个是非拷贝的。
- 结构:WinRT的结构类型,在JS也是以对象的形式表现的。如果要传递要给WinRT的结构给WinRT的方法,不要在JS中使用new来初始化这个结构。反之,直接在对象上添加所需要的属性(例如:
SomeStruct.firstMember
) - 对象:JS中的对象不是.NET中的托管对象,不能把一个JS对象传递给一个接受
System.Object
类型的WinRT方法 - 对象标识:大部分情况下,在JS和WinRT之间传递的对象是不变的。JS引擎会保持一个已知对象的映射。当JS从WinRT获取到一个对象时,会在这个映射表中做匹配,如果不存在的话会插入。这个对于WinRT方法返回的对象也是一样的操作。但是有下面几点例外:
- 从WinRT中返回的对象,如果添加了新(expando)的部属。在对象传回WinRT的时候新添加的部属不会跟随传入。但是因为有映射表在,从WinRT返回从前的对象的时候,从前对象的JS新增部属依然存在。
- 结构和委派类型在WinRT中以值的形式存在,前面创建的值和新创建的值不会相等,虽然都是以引用类型表示的。
- 名字冲突:不同的命名空间,可能有相同的成员,如果这些成员合并到同一个JS对象,那么需要以全前缀的方式引用:
Class["MemberName"](parameter)
namespace CollisionExample {
interface InterfaceA
{
HRESULT Draw([in] Int32 a);
}
interface InterfaceB
{
HRESULT Draw([in] HString a);
}
runtimeclass ExampleObject {
interface InterfaceA
interface InterfaceB
}
}
var example = new ExampleObject();
example["CollisionExample.InterfaceA.draw"](12);
example["CollisionExample.InterfaceB.draw"]("hello");
- 输出参数:如果一个WinRT方法有多个输出参数,那么这些参数会合成到要给JS对象返回:
void ExampleMethod(
[OutAttribute] char^ first,
[OutAttribute] char^ second
)
var returnValue = exampleMethod(); // returnValue包含first和second两个部属
- 静态成员:WinRT中有静态成员和实例成员。在JS中,静态成员被添加为WinRT运行类或者接口的对象部属:
// Static method.
var accel = Windows.Devices.Sensors.Accelerometer.getDefault();
// Instance method.
var reading = accel.getCurrentReading();
Using Windows Runtime Asynchronous Methods
WinRT中的异步操作在JS中采用Promise表示。在Promise的then或者done回调中,指定对异步操作返回结果的处理。下面是一个例子:
client.createResourceAsync(uri, description, item)
// Success.
.then(function(newItem) {
console.log("New item is: " + newItem.id);
},
// Error. 可选
function(error) {
alert("Failed to create a resource.");
},
// Progress. 可选
function(progress, resultSoFar) {
setProgressBar(progress);
});
或者
client.createResourceAsync(uri, description, item)
// Success.
.done(function(newItem) {
console.log("New item is: " + newItem.id);
});
then和done的区别是done会将异常抛出。
在JS中调试异步操作可能会比较麻烦,没有足够多的信息。为了改善这一点,调试状态下当WinRT异步操作返回错误的时候,错误对象上会新增一些额外的部属:
asyncOpSource
储存错误发生时的调用信息,asyncOpSource.originatingCall
是一个字符串,用于显示错误发生时的代码所在。asyncOpType
是一个字符串,可以用来获取发生错误的异步操作的类型。
Handling Windows Runtime Events in JavaScript
WinRT事件在JS中以小写字符串形式表示,可以被用来传入WinRT类的addEventListener和removeEventListener方法,比如Geolocator.PositionChanged事件:
var locator = new Windows.Devices.Geolocation.Geolocator();
locator.addEventListener(
"positionchanged",
function (ev) {
console.log("Got event");
});
另外也可以通过onpositionchanged
来侦听事件变化:
locator.onpositionchanged =
function (ev) {
console.log("Got event");
};
另外一个差异是 WinRT的事件委托一般接收的是两个参数,而JS中这些都是作为事件的部属传递的:
function (ev) {
console.log("Sender: " + ev.target);
console.log("Position: " +
ev.position.latitude + "," +
ev.position.longitude);
};
JavaScript Representation of Windows Runtime Types
WinRT类型在JS中的表示:
- Uint8,在JS中表示为Number,JS转WinRT的时候,先将JS的值转为Number,再使用ToUnit32方法,结果取2的8次方的模。
- Int32,在JS中表示为Number,JS转WinRT的时候,先将JS的值转为Number,再使用ToInit32方法,结果取2的16次方的模。
- Int64,在JS中表示为Number,这个处理起来比较复杂,因为JS的Number是double类型的,其浮点位为52个,指数位为11,符号为1。如果Int64超过了 [-2^53, 2^53]的范围,那么就可能会被视为计算错误。
- Uint64,在JS中表示为Number,跟Int64有点类似,取值范围最好在[0, 2^53]。
- Single(32位浮点),在JS中表示为Number,JS转WinRT的时候,如果结果不能用32位表示,会出错
- Double,在JS中表示为Number,算是和JS的Number精度匹配了,如果转化失败,则会出错
- Boolean,在JS中表示为Number,JS转WinRT的时候会调用ToBoolean,这意味着JS的字符串比如”test“可以被转为true
- Char16,在JS中表示为String,JS转WinRT的时候会调用ToString,结果必须是和Char16同长度,否则会出错
- String,在JS中表示为String,这两个算是比较匹配,不过JS的null和undefined会被转为"null"和"undefined",如果WinRT需要一个null字符串,则应该传一个JS的”“。
- Enumeration,在JS中表示为Object,各种枚举项目以Object的只读部属表示。由于Enumeration是无符号或者有符号的32位整型,所以上面描述的32位整型的转化也适用于枚举。但是从JS转WinRT的时候,不会检查值是否是枚举中有效的值。
- Structure,在JS中表示为Object,Structure是复合值,按照其所复合的项目,组成一个JS的Object。注意,Structure不能通过new关键字构建
- Array,在JS中表示为Array,注意的是,WinRT的Array是非可改的;其次,Array的
[[Class]]
也不能设置为Array,所以Array.isArray(v)返回false。注意的是,传一个JS的Array给需要WinRT Array的时候,会拷贝整个Array。 - Delegate (function callback),在JS中表示为Function。在WinRT中一个Delegate(委调)是一个函数的引用。在调用这个委调的时候,如果传的参数比实际的少,那么就会失败;如果比实际的多,那么多余的就会被忽略。输出的参数会打包作为一个JS对象的部属返回。如果一个原生的JS对象被转化为一个WinRT委调,那么它会被外套打包成一个原生的WinRT委调。
- Interface,在JS中表示为Object,接口或者接口族群并不直接映射为一个JS对象。如果一个接口有对应的runtimeclass,那么这个runtimeclass对应的JS对象会被用来当作接口的JS对象。如果没有,那么一个临时的JS对象就会被制作出来,用来表示这个接口。
- Runtime classes,在JS中表示为Object。这个容易对应。值得注意的是runtimeclass对应的JS对象,其原型对象包含了所有该runtimeclass的成员。
Windows Runtime DateTime and TimeSpan Representations
WinRT的DateTime比JS的Date精度要高。当WinRT的DateTime转为位JS对象是,也会转为Date对象,不过具有WInRT的精度。如果子啊JS中修改了从WinRT转化而来的Date对象,那么这个Date类对象就会变成一个普通的JS的Date对象。
WinRT的TimeSpan会被转为一个JS的Number,单位是毫秒。
Error codes for Windows Runtime apps using JavaScript
此章节列举了一些在Visual Studio console 会出现的错误代码。
MSApp
MSApp仅支持使用JS作为WinRT编程语言的项目(包括PWA)。MSApp对象只有在从ms-appx加载的HTML文档中可见。MSApp提供了对Blob和MSStream的支持。
其他
- Asynchronous programming in JavaScript (HTML)
- How to handle errors with promises (HTML)
- Troubleshooting Windows Runtime errors (HTML)
(完)