菜单

javascript异步编程

2019年7月7日 - 计算机教程

运行代码

script.onreadystatechange

function async(callback) { 
var script = document.createElement("script"); 
script.type = "text/javascript"; 
script.src = "javascript:"; 
script.onreadystatechange = function () { 
document.body.removeChild(script); 
callback(); 
} 
document.body.appendChild(script); 
} 
Bits Number Meaning
000000 0 元素一致
000001 1 节点在不同的文档(或者一个在文档之外)
000010 2 节点 B 在节点 A 之前
000100 4 节点 A 在节点 B 之前
001000 8 节点 B 包含节点 A
010000 16 节点 A 包含节点 B
100000 32 浏览器的私有使用

self.postMessage

function async(callback) { 
var n = ++async.count; 
window.addEventListener('message',function(e){ 
if (e.data == n) { 
window.removeEventListener('message', arguments.callee,false); 
callback(); 
} 
},false); 
window.postMessage(n, location.protocol + "//" + location.host); 
} 
async.count = 0; 

[Ctrl+A 全选 注:如需引入外部Js需刷新才能执行]

Chromium Safari Firefox Opera 10.10 Opera 10.50
setTimeout 4.32ms 10.201ms 10.302ms 10.38ms 9.876ms
img.onerror 0.199ms 0.678ms 0.201ms 0.058ms 0.575ms
script.onreadystatechange fail fail fail fail fail
script.onload 0.414ms 0.138ms 0.414ms fail fail
xhr.onreadystatechange fail 0.622ms fail 0.078ms 0.079ms
self.postMessage 0.096ms 0.123ms 0.112ms 0.049ms 0.094ms

为了处理这种异步调用,Mochikit从Python的Twisted框架借来了Deferred这个类,并用它来处理AJAX的回调。AJAX的回调通常有两种,成功加载时的回调与请求失败的回调,IE8的XDomainRequest就有这两种回调了,标准浏览器的script与image也有这两种回调,分别称之为onload与onerror。Mochikit的Deferred实例就内置一个数组,每次包含这两种回调,依次执行。Mochikit这伟大的遗产后来由dojo发扬光大了,至于怎么用,自己google吧。

402.com,下面是我的框架对它的应用,我已把它整合到我的框架中:

复制代码 代码如下:

<!doctype html>
<html>
<head>
<title>异步操作例子 by 司徒正美</title>
<meta charset=”utf-8″/>
<meta content=”IE=8″ http-equiv=”X-UA-Compatible”/>
<meta name=”keywords” content=”异步操作例子 by 司徒正美” />
<meta name=”description” content=”异步操作例子 by 司徒正美” />
<%= javascript_include_tag “dom.js” %>
<%= javascript_tag “window._token =
‘#{form_authenticity_token}'” if
ActionController::Base.allow_forgery_protection %>
<script type=”text/javascript” charset=”utf-8″>
dom.ready(function(){
dom.require(“ajax”);
dom.ajax({method:”post”,
async:true,
dataType:”text”,
data:{authenticity_token:window._token}
}).next(function(a){
alert(a)
});
dom.jsonp({url:”http://del.icio.us/feeds/json/fans/stomita"}).next(function(json){
alert(json)
}).error(function(e){
alert(e)
});
});
</script>
</head>
<body>
</body>
</html>

后台:

复制代码 代码如下:

class HomeController < ApplicationController
def index
if request.xhr?
name = params[:name]
puts “————-“
render :text => “<p>The time is <b>” + DateTime.now.to_s

在日本一博客提到这样一个捕捉异步错误的例子:

复制代码 代码如下:

function throwError(){
throw new Error(‘ERROR’);
}
try{
setTimeout(throwError, 3000);
} catch(e){
alert(e);
}

看来try…catch是无法捕捉这种形式的错误,window.onerror可以,但好像只有IE与FF支持。如果用Deferred来处理,就简单了!

复制代码 代码如下:

dom.Deferred.next(function () {
throw new Error(“错误”)
}).wait(1).error(function(e){
alert(e instanceof Error)
});

列队处理。由于是使用了异步,因此不会阻塞页面的演染。

复制代码 代码如下:

<!doctype html>
<html>
<head>
<title>异步操作例子 by 司徒正美</title>
<meta charset=”utf-8″/>
<meta content=”IE=8″ http-equiv=”X-UA-Compatible”/>
<meta name=”keywords” content=”异步操作例子 by 司徒正美” />
<meta name=”description” content=”异步操作例子 by 司徒正美” />
<%= javascript_include_tag “dom.js” %>
<script type=”text/javascript” charset=”utf-8″>
dom.require(“deferred”);
dom.require(“query”);
dom.ready(function(){
var a = dom(“#aaa”)[0];
dom.Deferred.loop(10,function(i){
a.innerHTML += i+”<br/>”
});
dom.Deferred.loop(10,function(i){
a.innerHTML += String.fromCharCode(i+97)+”<br/>”
});
dom.Deferred.loop(10,function(i){
a.innerHTML += “司徒正美”+i+”<br/>”
});
});
/*结果
0
a
司徒正美0
1

司徒正美1
2
c
司徒正美2
3
d
司徒正美3
4
e
司徒正美4
5
f
司徒正美5
6
g
司徒正美6
7
h
司徒正美7
8
i
司徒正美8
9
j
司徒正美9
*/
</script>
</head>
<body>
<div id=”aaa”></div>
</body>
</html>

http://www.bkjia.com/Javascript/322467.htmlwww.bkjia.comtruehttp://www.bkjia.com/Javascript/322467.htmlTechArticle就好像排队,前面的人忙着忙着突然上厕所了,后面的人阻塞在这里,因此我们就需要让前面的人死到一边去,让后面的人跟进……AJAX就是

<!doctype html> <title>dom contains 方法 by
司徒正美</title> <meta charset=”utf-8″/> <meta
name=”keywords” content=”dom contains 方法 by 司徒正美” /> <meta
name=”description” content=”dom contains 方法 by 司徒正美” />
<script type=”text/javascript”> window.onload = function(){ var A
= document.getElementById(‘parent’), B =
document.getElementById(‘child’); alert(A.contains(B));
alert(B.contains(A)); } </script> <h2
>contains方法</h2> <div id=”parent”> <p> <strong
id=”child” >本例子会在火狐中会报错。</strong> </p>
</div>

javascript中实现这个功能的是来自BOM的一个函数setTimeout,但相关的DOM操作也提供了一系列实现。如XMLHttpRequest对象与script标签的onreadystatechange回调,image的onload与onerror回调,iframe的onload,DOM元素的事件回调,HTML5的跨域消息传送postMessage,QuickTime与flash对象的加载……

运行代码

setTimeout (slow, takes about 10 sec)

function async(callback) { 
setTimeout(callback, 0); 
} 

<!doctype html> <title>dom contains 方法 by
司徒正美</title> <meta charset=”utf-8″/> <meta
name=”keywords” content=”dom contains方法 by 司徒正美” /> <meta
name=”description” content=”dom contains方法 by 司徒正美” />
<script type=”text/javascript”> if(!!window.find){
HTMLElement.prototype.contains = function(B){ return
this.compareDocumentPosition(B) – 19 > 0 } } window.onload =
function(){ var A = document.getElementById(‘parent’), B =
document.getElementById(‘child’); alert(A.contains(B));
alert(B.contains(A)); } </script> <h2
>contains方法</h2> <div id=”parent”> <p> <strong
id=”child” >contains方法</strong> </p> </div>

就好像排队,前面的人忙着忙着突然上厕所了,后面的人阻塞在这里,因此我们就需要让前面的人死到一边去,让后面的人跟进……AJAX就是这个概念,请求还在继续,但我们还可以做其他事。

     //2011.9.24 by 司徒正美              var contains  = function(root, el) {                  if (root.compareDocumentPosition)                      return root === el || !!(root.compareDocumentPosition(el) & 16);                  if (root.contains && el.nodeType === 1){                      return root.contains(el) && root !== el;                  }                  while ((el = el.parentNode))                      if (el === root) return true;                  return false;              }  

     //2013.1.24 by 司徒正美                   function contains(parentEl, el, container) {              // 第一个节点是否包含第二个节点             //contains 方法支持情况:chrome+ firefox9+ ie5+, opera9.64+(估计从9.0+),safari5.1.7+    if (parentEl == el) {     return true;    }    if (!el || !el.nodeType || el.nodeType != 1) {     return false;    }    if (parentEl.contains ) {     return parentEl.contains(el);    }    if ( parentEl.compareDocumentPosition ) {     return !!(parentEl.compareDocumentPosition(el) & 16);    }    var prEl = el.parentNode;    while(prEl && prEl != container) {     if (prEl == parentEl)      return true;     prEl = prEl.parentNode;    }    return false;   }  

xhr.onreadystatechange (data:text/plain,foo)

function async(callback) { 
var xhr = new XMLHttpRequest; 
xhr.open('GET','data:text/plain,foo',true); 
xhr.onreadystatechange = function() { 
xhr.onreadystatechange = null; 
callback(); 
}; 
xhr.send(null); 
} 

IE有许多好用的方法,后来都被其他浏览器抄袭了,比如这个contains方法。如果A元素包含B元素,则返回true,否则false。唯一不支持这个方法的是IE的死对头firefox。

img.onerror (data:uri)

function async(callback) { 
var img = new Image; 
img.addEventListener('error', callback, false); 
img.src = 'data:,foo'; 
} 

我搞出个更短的:

setTimeout的零秒延迟在前些年时间被国内宣扬得特别厉害,但setTimeout是所有延迟中最慢的,最少要花上10多毫秒,如果用setTimeout来开发特效,这特效会运行得比较慢。下面是一个性能测试:

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图