金沙澳门官网jin5888:深入理解Web,是否要学点GUI编程

金沙澳门官网jin5888:深入理解Web,是否要学点GUI编程。传统GUI编程相对于Web前端编程来说,应该要复杂点。以MVC的要求来看,大多数现有系统代码可能都不达标。但在Web领域,通过框架的约束,是个人都知道要MVC。

学习java开发的必学课程知识

【转向JavaScript系列】深入理解Web Worker

有别于Java/C#等编程语言,Javascript运行在一个单线程环境中,对setTimeout/setInterval、ajax和dom事件的异步处理是依赖事件循环实现的。作为一个转向Javascript的开发人员,很自然的产生一个疑问,如何实现Javascript多线程编程呢?随着学习的深入,我了解到HTML5
Web Worker,本文将分析Web
Worker为Javascript带来了什么,同时带大家看看worker模型在其他语言的应用。

MVC有Classic MVC和Web MVC,其主要的区别在于M与V是否耦合。Classic
MVC一直运用于传统GUI编程领域。

第一阶段 Java SE

Web Worker是什么

Web Worker 是HTML5标准的一部分,这一规范定义了一套
API,它允许一段JavaScript程序运行在主线程之外的另外一个线程中。Web
Worker 规范中定义了两类工作线程,分别是专用线程Dedicated
Worker和共享线程 Shared Worker,其中,Dedicated
Worker只能为一个页面所使用,而Shared
Worker则可以被多个页面所共享,本文示例为专用线程Dedicated Worker。

GUI编程中,会涉及阻塞与非阻塞,异步与同步、主线程与子线程等概念(在Web开发中也是存在的,但PHP中比较少);主线程一般不能被阻塞,不然界面就呈现卡住的状态,像搞安卓的初学者都知道这个原则,由此造成需要掌握一些比较复杂和精妙的编码方式。

第二阶段 Web前端基础篇—HTML4+CSS2+JavaScript+jQuery

API快速上手

使用Dedicated Worker的主页面代码main.js

var worker = new Worker("task.js");
worker.postMessage(
        {
            id:1,
            msg:'Hello World'
        }
);
worker.onmessage=function(message){
    var data = message.data;
    console.log(JSON.stringify(data));
 worker.terminate();
};
worker.onerror=function(error){
    console.log(error.filename,error.lineno,error.message);
}

Dedicated Worker所执行的代码task.js

onmessage = function(message){
    var data=message.data;
    data.msg = 'Hi from task.js';
    postMessage(data);
}

在main.js代码中,首先通过调用构造函数,传入了worker脚本文件名,新建了一个worker对象,在我的理解中,这一对象是新创建的工作线程在主线程的引用。随后调用worker.postMessage()方法,与新创建的工作线程通信,这里传入了一个json对象。随后分别定义了worker对象的onmessage事件和onerror事件的回调处理函数,当woker线程返回数据时,onmessage回调函数执行,数据封装在message参数的data属性中,调用
worker 的
terminate()方法可以终止worker线程的运行;当worker线程执行出错时,onerror回调函数执行,error参数中封装了错误对象的文件名、出错行号和具体错误信息。

在task.js代码中,定义了onmessage事件处理函数,由主线程传入的数据,封装在message对象的data属性中,数据处理完成后,通过postMessage方法完成与主线程通信。在工作线程代码中,onmessage事件和postMessage方法在其全局作用域可以访问。

随着Web标准的进化,现在基于Web开发的纯客户端GUI程序也越来越多,像有道词典、钉钉、bearychat等都是比较成功的案例。

第三阶段 JavaEE基础篇—Servlet+JSP+AJAX

worker线程执行流程

通过查阅资料,webKit加载并执行worker线程的流程如下图所示

金沙澳门官网jin5888:深入理解Web,是否要学点GUI编程。1

  • 金沙澳门官网jin5888:深入理解Web,是否要学点GUI编程。worker线程的创建的是异步的
    代码执行到”var worker = new
    Worker(task.js’)“时,在内核中构造WebCore::JSWorker对象(JSBbindings层)以及对应的WebCore::Worker对象(WebCore模块),根据初始化的url地址”task.js”发起异步加载的流程;主线程代码不会阻塞在这里等待worker线程去加载、执行指定的脚本文件,而是会立即向下继续执行后面代码。
  • postMessage消息交互由内核调度
    main.js中,在创建woker线程后,立即调用了postMessage方法传递了数据,在worker线程还没创建完成时,main.js中发出的消息,会先存储在一个临时消息队列中,当异步创建worker线程完成,临时消息队列中的消息数据复制到woker对应的WorkerRunLoop的消息队列中,worker线程开始处理消息。在经过一轮消息来回后,继续通信时,
    这个时候因为worker线程已经创建,所以消息会直接添加到WorkerRunLoop的消息队列中;

GUI编程其实比较重要,我们用的桌面操作系统、各种工具软件都要很专业很强悍的技术沉淀,但大家也会更多的尝试成本更低的方向。

第四阶段 数据库篇——Oracle

worker线程数据通讯方式

主线程与子线程数据通信方式有多种,通信内容,可以是文本,也可以是对象。需要注意的是,这种通信是拷贝关系,即是传值而不是地址,子线程对通信内容的修改,不会影响到主线程。事实上,浏览器内部的运行机制是,先将通信内容串行化,然后把串行化后的字符串发给子线程,后者再将它还原。
主线程与子线程之间也可以交换二进制数据,比如File、Blob、ArrayBuffer等对象,也可以在线程之间发送。但是,用拷贝方式发送二进制数据,会造成性能问题。比如,主线程向子线程发送一个50MB文件,默认情况下浏览器会生成一个原文件的拷贝。为了解决这个问题,JavaScript允许主线程把二进制数据直接转移给子线程,转移后主线程无法再使用这些数据,这是为了防止出现多个线程同时修改数据的问题,这种转移数据的方法,叫做Transferable
Objects。

// Create a 32MB "file" and fill it.
var uInt8Array = new Uint8Array(1024*1024*32); // 32MB
for (var i = 0; i < uInt8Array .length; ++i) {
    uInt8Array[i] = i;
}
worker.postMessage(uInt8Array.buffer, [uInt8Array.buffer]);

第五阶段 MVC——SpringMVC+Mybatis

API进阶

在worker线程中,可以获得下列对象

  • navigator对象
  • location对象,只读
  • XMLHttpRequest对象
  • setTimeout/setInterval方法
  • Application Cache
  • 通过importScripts()方法加载其他脚本
  • 创建新的Web Worker

worker线程不能获得下列对象

  • DOM对象
  • window对象
  • document对象
  • parent对象

上述的规范,限制了在worker线程中获得主线程页面相关对象的能力,所以在worker线程中,不能进行dom元素的更新。

1、我们必须明确一个大方向,也就是说现在面向对象的编程范畴。尽管人工智能曾经有所浪潮(看看

似曾相识worker模型

我在学习Web
Worker过程中,总有一种似曾相似的感觉。在以往的学习经验中,了解过Java
Swing GUI库中的Swing Worker,我们可以看看worker模型在Swing中的应用。

Borland为什么有Turbo
Prolog),但未来5-10年工业界广泛承认并接受的将是面向对象式的编程。

Swing事件分发模型

同Winform/WPF等其他GUI库一样,Swing是一个基于事件队列的单线程编程模型。Swing将GUI请求放入一个事件队列EventQueue
中等待执行,EventQueue的派发机制由单独的一个线程管理,这个线程称为事件派发线程(EventDispatchThread),负责GUI组件的绘制和更新。这一事件分发模型如下图所示:

2

Swing单线程模型的一个问题是,如果在“事件派发线程”上执行的运算太多,那么GUI界面就会停住,系统响应和运算就会非常缓慢。

既然事件派发线程是为了处理GUI事件而设的,那么,我们只应该把GUI事件处理相关的代码,放在事件派发线程中执行。其他与界面无关的代码,应该放在Java其他的线程中执行。这样,我们在Swing的事件处理中,仍然使用Swing的单线程编程模型,而其他业务操作均使用多线程编程模型,这就可以大大提高Swing程序的响应和运行速度,充分运用Java多线程编程的优势。

2、工业界目前最流行的面向对象编程语言就是C++和Java。所以基本上锁定这两个方向就可以了。而且

Swing Worker

Java SE 6提供了javax.swing.SwingWorker类,Swing Worker
设计用于需要在后台线程中运行长时间运行任务的情况,并可在完成后或者在处理过程中向
UI 提供更新。

假定我们在UI界面点击一次下载按钮,在按钮的事件处理函数中,需要去加载一张Icon图片,图片加载完成后,将icon在UI界面展示出来。

SwingWorker testWorker = new SwingWorker<Icon , Void>(){  
      @Override  
       protected Icon doInBackground() throws Exception {  
        Icon icon = retrieveImage(strImageUrl);   
            return icon;   
       }   

       protected void done(){   
            Icon icon= get();  
            lblImage.setIcon(icon); //lblImage可通过构造函数传入  
      }             
}  
testWorker.execute();

上述代码中,我们在按钮的事件处理函数中,创建了一个swingworker实例对象。调用构造函数时,指定第一个泛型参数为Icon,这是一个自定义类型,这里代表一个Icon图片对象。指定这一泛型参数,是为了指定doInBackground()方法的返回值,并在done()方法中获取。

doInBackground方法作为工作线程的一部分执行,它负责完成线程的基本任务,并以返回值来作为线程的执行结果。在doInBackground方法完成之后,SwingWorker调用done方法。如果任务需要在完成后,使用工作线程执行结果来更新GUI组件或者做些清理工作,可覆盖done方法来完成它们。使用SwingWorker的get方法可以获取doInBackground方法的结果,done方法是调用get方法的最好地方,因为此时已知道线程任务完成了,SwingWorker在EDT上激活done方法,因此可以在此方法内安全地和任何GUI组件交互。execute方法是异步执行,它立即返回到调用者。在execute方法执行后,EDT立即继续执行。

完全可以同时掌握。

WebWorker vs SwingWorker

Swing Worker还有一些其他的方法,这里不再讨论。我们可以结合Web
Worker,对比看看两者异同。

两者编程模型相同,都是在主线程中,将耗时工作交由工作线程去异步的完成,从而避免主线程的阻塞。

两者线程通信机制不同,Web
Worker线程通信限制严格,仅能通过postMessage方法通信,而且参数传递均为值传递,没有引用传递;Swing
Worker参数传递灵活,上述事例中,testWorker的doInBackground方法直接引用了strImageUrl变量,不过这一方式并不推荐,而是应当定义一个新类继承自SwingWorker,并在构造函数中传入imgUrl变量,然后在实例化worker线程中传入变量。

两者对UI界面的更新限制不同,Web
Worker禁止在worker线程中操作dom元素,所以不能在worker中更新UI;Swing
Worker允许在done方法中更新UI,这里并没有违背Swing的事件分发模型,因为最终还是在EDT上激活的done方法,依然遵循着事件分发模型。

3、掌握Java的精华特性而且一定要知道为什么。比如,Interface和multi-thread。用interface是更

Web Worker带来了什么

最后来总结Web
Worker为javascript带来了什么,学习过程中,看到一些文章认为Web
Worker为Javascript带来了多线程编程能力,我不认可这种观点。

相关文章