JQuery中的Deferred-详解和使用

 

首先,为什么要使用Deferred?

先来看一段AJAX的代码:

1     var data;
2     $.get('api/data', function(resp) {
3         data = resp.data;
4     });
5     doSomethingFancyWithData(data);
View Code

这段代码极容易出问题,请求时间多长或者超时,将会导致我们获取不到data。只有把请求设置为同步我们才能够等待获取到data,才执行我们的函数。但是这会带来阻塞,导致用户界面一直被冻结,对用户体验有很严重的影响。所以我们需要使用异步编程,

JS的异步编程有两种方式基于事件和基于回调,

传统的异步编程会带来的一些问题,

1.序列化异步操作导致的问题:

  1),延续传递风格Continuation Passing Style (CPS)

      2),深度嵌套

     3),回调地狱

2.并行异步操作的困难

 

下面是一段序列化异步操作的代码:

复制代码
 1 // Demonstrates nesting, CPS, 'callback hell'
 2 $.get('api1/data', function(resp1) {
 3     // Next that depended on the first response.
 4     $.get('api2/data', function(resp2) {
 5         // Next request that depended on the second response.
 6         $.get('api3/data', function(resp3) {
 7             // Next request that depended on the third response.
 8             $.get(); // ... you get the idea.
 9         });
10     });
11 });
复制代码
View Code

当回调越来越多,嵌套越深,代码可读性就会越来越差。如果注册了多个回调,那更是一场噩梦!

再看另一段有关并行化异步操作的代码:

复制代码
$.get('api1/data', function(resp1) { trackMe(); });
$.get('api2/data', function(resp2) { trackMe(); });
$.get('api3/data', function(resp3) { trackMe(); });
var trackedCount = 0;
function trackMe() {++trackedCount;if (trackedCount === 3) {doSomethingThatNeededAllThree();}
}
复制代码
View Code

上面的代码意思是当三个请求都成功就执行我们的函数(只执行一次),毫无疑问,这段代码有点繁琐,而且如果我们要添加失败回调将会是一件很麻烦的事情。

 

我们需要一个更好的规范,那就是Promise规范,这里引用Aaron的一篇文章中的一段,http://www.cnblogs.com/aaronjs/p/3163786.html:

  • 在我开始promise的“重点”之前,我想我应该给你一点它们如何工作的内貌。一个promise是一个对象——根据Promise/A规范——只需要一个方法:then。then方法带有三个参数:一个成功回调,一个失败回调,和一个前进回调(规范没有要求包括前进回调的实现,但是很多都实现了)。一个全新的promise对象从每个then的调用中返回。
  • 一个promise可以是三种状态之一:未完成的,完成的,或者失败的。promise以未完成的状态开始,如果成功它将会是完成态,如果失败将会是失败态。当一个promise移动到完成态,所有注册到它的成功回调将被调用,而且会将成功的结果值传给它。另外,任何注册到promise的成功回调,将会在它已经完成以后立即被调用。

  • 同样的事情发生在promise移动到失败态的时候,除了它调用的是失败回调而不是成功回调。对包含前进特性的实现来说,promise在它离开未完成状态以前的任何时刻,都可以更新它的progress。当progress被更新,所有的前进回调(progress callbacks)会被传递以progress的值,并被立即调用。前进回调被以不同于成功和失败回调的方式处理;如果你在一个progress更新已经发生以后注册了一个前进回调,新的前进回调只会在它被注册以后被已更新的progress调用。
  • 我们不会进一步深入promise状态是如何管理的,因为那不在规范之内,而且每个实现都有差别。在后面的例子中,你将会看到它是如何完成的,但目前这就是所有你需要知道的。

 

现在有不少库已经实现了Deferred的操作,其中jQuery的Deferred就非常热门:

先过目一下Deferred的API:

 

jQuery的有关Deferred的API简介:

复制代码
 1 $.ajax('data/url')
 2     .done(function(response, statusText, jqXHR){
 3         console.log(statusText);
 4     })
 5     .fail(function(jqXHR, statusText, error){
 6         console.log(statusText);
 7     })
 8     ,always(function(){
 9         console.log('I will always done.');
10     });
复制代码
View Code

1.done,fail,progress都是给回调列表添加回调,因为jQuery的Deferred内部使用了其$.Callbacks对象,并且增加了memory的标记(详情请查看我的这篇文章jQuery1.9.1源码分析--Callbacks对象),

所以如果我们第一次触发了相应的回调列表的回调即调用了resolve,resolveWith,reject,rejectWith或者notify,notifyWith这些相应的方法,当我们再次给该回调列表添加回调时,就会立刻触发该回调了,

即使用了done,fail,progress这些方法,而不需要我们手动触发。jQuery的ajax会在请求完成后就会触发相应的回调列表。所以我们后面的链式操作的注册回调有可能是已经触发了回调列表才添加的,所以它们就会立刻被执行。

2.always方法则是不管成功还是失败都会执行该回调。

接下来要介绍重量级的then方法(也是pipe方法):

3.then方法会返回一个新的Deferred对象
* 如果then方法的参数是deferred对象,
* 上一链的旧deferred会调用[ done | fail | progress ]方法注册回调,该回调内容是:执行then方法对应的参数回调(fnDone, fnFail, fnProgress)。
* 1)如果参数回调执行后返回的结果是一个promise对象,我们就给该promise对象相应的回调列表添加回调,该回调是触发then方法返回的新promise对象的成功,失败,处理中(done,fail,progress)的回调列表中的所有回调。
* 当我们再给then方法进行链式地添加回调操作(done,fail,progress,always,then)时,就是给新deferred对象注册回调到相应的回调列表。
* 如果我们then参数fnDoneDefer, fnFailDefer, fnProgressDefer得到了解决,就会执行后面链式添加回调操作中的参数函数。
*
* 2)如果参数回调执行后返回的结果returned不是promise对象,就立刻触发新deferred对象相应回调列表的所有回调,且回调函数的参数是先前的执行返回结果returned。
* 当我们再给then方法进行链式地添加回调操作(done,fail,progress,always,then)时,就会立刻触发我们添加的相应的回调。
*
* 可以多个then连续使用,此功能相当于顺序调用异步回调。

 

复制代码
 1 $.ajax({
 2                            url: 't2.html',
 3                            dataType: 'html',
 4                            data: {
 5                               d: 4
 6                            }
 7                         }).then(function(){
 8                             console.log('success');
 9                         },function(){
10                             console.log('failed');
11                         }).then(function(){
12                             console.log('second');
13                             return $.ajax({
14                                 url: 'jquery-1.9.1.js',
15                                 dataType: 'script'
16                             });
17                         }, function(){
18                             console.log('second f');
19                             return $.ajax({
20                                 url: 'jquery-1.9.1.js',
21                                 dataType: 'script'
22                             });
23                         }).then(function(){
24                             console.log('success2');
25                         },function(){
26                             console.log('failed2');
27                         });
复制代码
View Code

上面的代码,如果第一个对t2.html的请求成功输出success,就会执行second的ajax请求,接着针对该请求是成功还是失败,执行success2或者failed2。

如果第一个失败输出failed,然后执行second f的ajax请求(注意和上面的不一样),接着针对该请求是成功还是失败,执行success2或者failed2。

理解这些对失败处理很重要。

 

将我们上面序列化异步操作的代码使用then方法改造后,代码立马变得扁平化了,可读性也增强了:

复制代码
 1     var req1 = $.get('api1/data');
 2     var req2 = $.get('api2/data');
 3     var req3 = $.get('api3/data');
 4 
 5     req1.then(function(req1Data){
 6         return req2.done(otherFunc);
 7     }).then(function(req2Data){
 8         return req3.done(otherFunc2);
 9     }).then(function(req3Data){
10         doneSomethingWithReq3();
11     });
复制代码
View Code

 

4.接着介绍$.when的方法使用,主要是对多个deferred对象进行并行化操作,当所有deferred对象都得到解决就执行后面添加的相应回调。

复制代码
 1     $.when(
 2         $.ajax({
 3             
 4             url: 't2.html'
 5         
 6         }),
 7         $.ajax({
 8             url: 'jquery-1.9.1-study.js'
 9         })
10     ).then(function(FirstAjaxSuccessCallbackArgs, SecondAjaxSuccessCallbackArgs){
11         console.log('success');
12     }, function(){
13         console.log('failed');
14     });
复制代码
View Code

如果有一个失败了都会执行失败的回调。

将我们上面并行化操作的代码改良后:

1     $.when(
2         $.get('api1/data'),
3         $.get('api2/data'),
4         $.get('api3/data'),
5         { key: 'value' }
6     ).done();
View Code

 

5.promse方法是返回的一个promise对象,该对象只能添加回调或者查看状态,但不能触发。我们通常将该方法暴露给外层使用,而内部应该使用deferred来触发回调。

 

如何使用deferred封装异步函数

 第一种:

复制代码
 1 function getData(){
 2   // 1) create the jQuery Deferred object that will be used
 3   var deferred = $.Deferred();
 4   // ---- AJAX Call ---- //
 5   var xhr = new XMLHttpRequest();
 6   xhr.open("GET","data",true);
 7   
 8   // register the event handler
 9   xhr.addEventListener('load',function(){
10     if(xhr.status === 200){
11       // 3.1) RESOLVE the DEFERRED (this will trigger all the done()...)
12       deferred.resolve(xhr.response);
13     }else{
14       // 3.2) REJECT the DEFERRED (this will trigger all the fail()...)
15       deferred.reject("HTTP error: " + xhr.status);
16     }
17   },false) 
18   
19   // perform the work
20   xhr.send();
21   // Note: could and should have used jQuery.ajax. 
22   // Note: jQuery.ajax return Promise, but it is always a good idea to wrap it
23   //       with application semantic in another Deferred/Promise  
24   // ---- /AJAX Call ---- //
25   
26   // 2) return the promise of this deferred
27   return deferred.promise();
28 }
复制代码
View Code

第二种方法:

1 function prepareInterface() {   
2    return $.Deferred(function( dfd ) {   
3        var latest = $( “.news, .reactions” );  
4        latest.slideDown( 500, dfd.resolve );  
5        latest.addClass( “active” );  
6     }).promise();   
7 }
View Code

 

 

Deferred的一些使用技巧:

 1.异步缓存

以ajax请求为例,缓存机制需要确保我们的请求不管是否已经存在于缓存,只能被请求一次。 因此,为了缓存系统可以正确地处理请求,我们最终需要写出一些逻辑来跟踪绑定到给定url上的回调。

 

复制代码
 1     var cachedScriptPromises = {};
 2 
 3     $.cachedGetScript =  function(url, callback){
 4         if(!cachedScriptPromises[url]) {
 5             cachedScriptPromises[url] = $.Deferred(function(defer){
 6                 $.getScript(url).then(defer.resolve, defer.reject);
 7             }).promise();
 8         }
 9 
10         return cachedScriptPromises[url].done(callback);
11     };
复制代码
View Code

 

我们为每一个url缓存一个promise对象。 如果给定的url没有promise,我们创建一个deferred,并发出请求。 如果它已经存在我们只需要为它绑定回调。 该解决方案的一大优势是,它会透明地处理新的和缓存过的请求。 另一个优点是一个基于deferred的缓存 会优雅地处理失败情况。 当promiserejected状态结束的话,我们可以提供一个错误回调来测试:

$.cachedGetScript( url ).then( successCallback, errorCallback );

请记住:无论请求是否缓存过,上面的代码段都会正常运作!

 

通用异步缓存

为了使代码尽可能的通用,我们建立一个缓存工厂并抽象出实际需要执行的任务

复制代码
 1     $.createCache = function(requestFunc){
 2         var cache = {};
 3 
 4         return function(key, callback){
 5             if(!cache[key]) {
 6                 cache[key] = $.Deferred(function(defer){
 7                     requestFunc(defer, key);
 8                 }).promise();
 9             }
10 
11             return cache[key].done(callback);
12         };
13     };
14 
15 
16     // 现在具体的请求逻辑已经抽象出来,我们可以重新写cachedGetScript:
17     $.cachedGetScript = $.createCache(function(defer, url){
18         $.getScript(url).then(defer.resolve, defer.reject);
19     });
复制代码
View Code

我们可以使用这个通用的异步缓存很轻易的实现一些场景:

图片加载

复制代码
 1 // 确保我们不加载同一个图像两次
 2     $.loadImage = $.createCache(function(defer, url){
 3         var image = new Image();
 4         function clearUp(){
 5             image.onload = image.onerror = null;
 6         }
 7         defer.then(clearUp, clearUp);
 8         image.onload = function(){
 9             defer.resolve(url);
10         };
11         image.onerror = defer.reject;
12         image.src = url;
13     });
14 
15     // 无论image.png是否已经被加载,或者正在加载过程中,缓存都会正常工作。
16     $.loadImage( "my-image.png" ).done( callback1 );  
17     $.loadImage( "my-image.png" ).done( callback1 );  
复制代码
View Code

缓存响应数据

复制代码
 1     $.searchTwitter = $.createCache(function(defer, query){
 2         $.ajax({
 3             url: 'http://search.twitter.com/search.json',
 4             data: {q: query}, 
 5             dataType: 'jsonp'
 6         }).then(defer.resolve, defer.reject);
 7     });
 8 
 9 // 在Twitter上进行搜索,同时缓存它们
10     $.searchTwitter( "jQuery Deferred", callback1 ); 
复制代码
View Code

定时, 

基于deferred的缓存并不限定于网络请求;它也可以被用于定时目的。

 

复制代码
 1     // 新的afterDOMReady辅助方法用最少的计数器提供了domReady后的适当时机。 如果延迟已经过期,回调会被马上执行。
 2     $.afterDOMReady = (function(){
 3         var readyTime;
 4         
 5         $(function(){
 6             readyTime = (new Date()).getTime();
 7         });
 8 
 9         return $.createCache(function(defer, delay){
10             delay = delay || 0;
11 
12             $(function(){
13                 var delta = (new Date()).getTime() - readyTime;
14 
15                 if(delta >= delay) {
16                     defer.resolve();
17                 } else {
18                     setTimeout(defer.resolve, delay - delta);
19                 }
20             });
21         });
22     })();
复制代码
View Code

 

 

2.同步多个动画

复制代码
 1     var fadeLi1Out = $('ul > li').eq(0).animate({
 2         opacity: 0
 3     }, 1000);
 4     var fadeLi2In = $('ul > li').eq(1).animate({
 5         opacity: 1
 6     }, 2000);
 7 
 8      // 使用$.when()同步化不同的动画
 9     $.when(fadeLi1Out, fadeLi2In).done(function(){
10         alert('done');
11     });
复制代码
View Code

虽然jQuery1.6以上的版本已经把deferred包装到动画里了,但如果我们想要手动实现,也是一件很轻松的事:

复制代码
 1 $.fn.animatePromise = function( prop, speed, easing, callback ) {   
 2     var elements = this;   
 3 
 4     return $.Deferred(function( defer ) {   
 5         elements.animate( prop, speed, easing, function() {   
 6             defer.resolve();   
 7             if ( callback ) {   
 8                 callback.apply( this, arguments );  
 9             }   
10         });   
11     }).promise();  
12 };
13 
14 // 我们也可以使用同样的技巧,建立了一些辅助方法:
15 $.each([ "slideDown", "slideUp", "slideToggle", "fadeIn", "fadeOut", "fadeToggle" ],   
16 function( _, name ) {   
17     $.fn[ name + "Promise" ] = function( speed, easing, callback ) {  
18         var elements = this;   
19         return $.Deferred(function( defer ) {   
20             elements[ name ]( speed, easing, function() {   
21                 defer.resolve();   
22                 if ( callback ) {   
23                 callback.apply( this, arguments );   
24                 }   
25             });  
26          }).promise();   
27     };   
28 });
复制代码
View Code

 

 

3.一次性事件

例如,您可能希望有一个按钮,当它第一次被点击时打开一个面板,面板打开之后,执行特定的初始化逻辑。 在处理这种情况时,通常会这样写代码:

复制代码
1 var buttonClicked = false;   
2 $( "#myButton" ).click(function() {   
3     if ( !buttonClicked ) {   
4         buttonClicked = true;   
5         initializeData();   
6         showPanel();   
7     }   
8 }); 
复制代码
View Code

这是一个非常耦合的解决办法。 如果你想添加一些其他的操作,你必须编辑绑定代码或拷贝一份。 如果你不这样做,你唯一的选择是测试buttonClicked。由于buttonClicked可能是false,新的代码可能永远不会被执行,因此你 可能会失去这个新的动作。

使用deferreds我们可以做的更好 (为简化起见,下面的代码将只适用于一个单一的元素和一个单一的事件类型,但它可以很容易地扩展为多个事件类型的集合):

 

复制代码
 1 $.fn.bindOnce = function(event, callback){
 2     var element = this;
 3     defer = element.data('bind_once_defer_' + event);
 4 
 5     if(!defer) {
 6         defer = $.Deferred();
 7 
 8         function deferCallback(){
 9             element.off(event, deferCallback);
10             defer.resolveWith(this, arguments);
11         }
12 
13         element.on(event, deferCallback);
14         element.data('bind_once_defer_' + event, defer);
15     }
16 
17     return defer.done(callback).promise();
18 };
19 
20 $.fn.firstClick = function( callback ) {   
21        return this.bindOnce( "click", callback );  
22  };  
23 
24 var openPanel = $( "#myButton" ).firstClick();   
25 openPanel.done( initializeData );   
26 openPanel.done( showPanel ); 
复制代码
View Code

 

该代码的工作原理如下:

· 检查该元素是否已经绑定了一个给定事件的deferred对象

· 如果没有,创建它,使它在触发该事件的第一时间解决

· 然后在deferred上绑定给定的回调并返回promise

4.多个组合使用

单独看以上每个例子,deferred的作用是有限的 。 然而,deferred真正的力量是把它们混合在一起。

*在第一次点击时加载面板内容并打开面板

 

假如,我们有一个按钮,可以打开一个面板,请求其内容然后淡入内容。使用我们前面定义的方法,我们可以这样做:

复制代码
1 var panel = $('#myPanel');
2 panel.firstClick(function(){
3     $.when(
4         $.get('panel.html'),
5         panel.slideDown()
6     ).done(function(ajaxArgs){
7         panel.html(ajaxArgs[0]).fadeIn();
8     });
9 });
复制代码
View Code

*在第一次点击时载入图像并打开面板

假如,我们已经的面板有内容,但我们只希望当第一次单击按钮时加载图像并且当所有图像加载成功后淡入图像。HTML代码如下:

复制代码
 1 <div id="myPanel">   
 2 <img data-src="image1.png" />  
 3  <img data-src="image2.png" />  
 4  <img data-src="image3.png" />   
 5 <img data-src="image4.png" />   
 6 </div>
 7 
 8 /*
 9 我们使用data-src属性描述图片的真实路径。 那么使用deferred来解决该用例的代码如下:
10 */
11 $('#myBtn').firstClick(function(){
12     var panel = $('#myPanel');
13     var promises = [];
14 
15     $('img', panel).each(function(){
16         var image = $(this);
17         var src = element.data('src');
18 
19         if(src) {
20             promises.push(
21                 $.loadImage(src).then(function(){
22                     image.attr('src', src);
23                 }, function(){
24                     image.attr('src', 'error.png');
25                 })
26             );
27         }
28     });
29 
30     promises.push(panel.slideDown);
31 
32     $.when.apply(null, promises).done(function(){
33         panel.fadeIn();
34     });
35 });
复制代码
View Code

*在特定延时后加载页面上的图像

假如,我们要在整个页面实现延迟图像显示。 要做到这一点,我们需要的HTML的格式如下:

 

复制代码
 1 <img data-src="image1.png" data-after="1000" src="placeholder.png" />   
 2     <img data-src="image2.png" data-after="1000" src="placeholder.png" />   
 3     <img data-src="image1.png" src="placeholder.png" />   
 4     <img data-src="image2.png" data-after="2000" src="placeholder.png" /> 
 5 
 6 /*
 7 意思非常简单:
 8 image1.png,第三个图像立即显示,一秒后第一个图像显示
 9 image2.png 一秒钟后显示第二个图像,两秒钟后显示第四个图像
10 */
11 
12 $( "img" ).each(function() {  
13     var element = $( this ),  
14         src = element.data( "src" ),  
15         after = element.data( "after" );  
16     if ( src ) {  
17         $.when(  
18             $.loadImage( src ),  
19             $.afterDOMReady( after )  
20         ).then(function() {  
21             element.attr( "src", src );  
22         }, function() {  
23             element.attr( "src", "error.png" );  
24         } ).done(function() {  
25             element.fadeIn();  
26         });  
27     }  
28 }); 
29 
30 // 如果我们想延迟加载的图像本身,代码会有所不同:
31 $( "img" ).each(function() {  
32     var element = $( this ),  
33         src = element.data( "data-src" ),  
34         after = element.data( "data-after" );  
35     if ( src ) {  
36         $.afterDOMReady( after, function() {  
37             $.loadImage( src ).then(function() {  
38                 element.attr( "src", src );  
39             }, function() {  
40                 element.attr( "src", "error.png" );  
41             } ).done(function() {  
42                 element.fadeIn();  
43             });  
44         } );  
45     }  
46 });  
复制代码
View Code

 

这里,我们首先在尝试加载图片之前等待延迟条件满足。当你想在页面加载时限制网络请求的数量会非常有意义。

 

 

Deferred的使用场所:

  • Ajax(XMLHttpRequest)
  • Image Tag,Script Tag,iframe(原理类似)
  • setTimeout/setInterval
  • CSS3 Transition/Animation
  • HTML5 Web Database
  • postMessage
  • Web Workers
  • Web Sockets
  • and more…

 

转载于:https://www.cnblogs.com/dylanblog/p/7169069.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/429073.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Eclipse】eclipse在线安装反编译插件

1.help->install new software 2.Add Name&#xff1a;jd-eclipse_update_site Location&#xff1a;http://jd.benow.ca/jd-eclipse/update 3.等待加载出来 4.持续点击下一步&#xff0c;直到完成。 转载于:https://www.cnblogs.com/flydkPocketMagic/p/7170283.html

Spring Boot 系列(一)快速入门

简介 Spring Boot是由Pivotal团队提供的全新框架&#xff0c;其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置&#xff0c;从而使开发人员不再需要定义样板化的配置。通过这种方式&#xff0c;Spring Boot致力于在蓬勃发展的快速应…

1. 在虚拟机中 添加内容

步骤&#xff1a; 1. 找到要添加的内容&#xff0c;按住 ctrl c 复制 &#xff0c;例如&#xff1a;复制 飞秋 2. 打开 虚拟机&#xff0c;找到 要复制文件的位置。 3. 将 复制的文件添加到 共享文件夹下面。 4. 打开虚拟机&#xff0c;安装飞秋 5&#xff0c; 最后就完成了…

java web scala_spring boot+scala编写web接口

本人是Java开发者&#xff0c;有面向对象的基础&#xff0c;而Scala也是面向对象的语言&#xff0c;学习后可快速入门。通过学习Scala的面向对象(和java面向对象类似)、Scala的高级函数(map,reduce等&#xff0c;和Java8中的stream编程类似)、Scala的隐式转换(在Java中可通过sp…

java小应用_java小应用

第一次使用简书记笔记&#xff0c;主要目的是为了加深印象&#xff0c;方便忘记时及时翻看。hello.java代码如下&#xff1a;import java.applet.Applet;import java.awt.*;public class hello extends Applet{private Font f1;public void init(){f1 new Font("宋体&quo…

java做橡皮擦效果_HTML5 canvas橡皮擦擦拭效果

这是一款HTML5 canvas橡皮擦擦拭效果。该效果通过canvas来制作遮罩层和擦拭用的橡皮擦&#xff0c;用户可以通过移动鼠标来移除遮罩层&#xff0c;效果非常炫酷。因为发代码有时会排版混乱&#xff0c;所以先发图演示了。源码已经打包好了&#xff0c;想学习的朋友可以下载练习…

mysql to mssql_MysqlToMsSql

MysqlToMsSql是一款简单易用的数据库迁移工具&#xff0c;这款软件功能强大&#xff0c;可以帮助用户将MySQL数据库内容转移到msSQL数据库中&#xff0c;采用可视化操作&#xff0c;支持预览&#xff0c;方便用户查看数据库&#xff0c;实用性强&#xff0c;有需要的用户快来下…

java延迟覆盖_高效Java第九条覆盖equals时总要覆盖hashCode

原标题&#xff1a;高效Java第九条覆盖equals时总要覆盖hashCode高效Java第九条覆盖equals时总要覆盖hashCode在每个覆盖了equals方法的类中&#xff0c;也必须覆盖hashCode方法。否则会导致该类无法与基于散列的集合一起正常运作。 hashCode约定在应用程序的执行期间&#xff…

原生js简单实现双向数据绑定原理

根据对象的访问器属性去监听对象属性的变化&#xff0c;访问器属性不能直接在对象中设置&#xff0c;而必须通过 defineProperty() 方法单独定义。 访问器属性的"值"比较特殊&#xff0c;读取或设置访问器属性的值&#xff0c;实际上是调用其内部特性&#xff1a;get…

java中write方法报错_Java中管道报错:Write end dead

今天看了下关于管道的通信&#xff0c;Java中的管道只能在同一进程的不同线程间通信。今天测试两个线程进行通信发现报错。下面是我测试的代码。package com.wpl.testIO;import java.io.IOException;import java.io.PipedInputStream;import java.io.PipedOutputStream;public …

神盾局特工第四季/全集Agents Of SHIELD迅雷下载

英文全名Agents Of SHIELD&#xff0c;第4季(2016)ABC. 本季看点&#xff1a;《神盾局特工》&#xff08;Agents Of SHIELD&#xff09;第三季季终集里&#xff0c;我们终于知道谁死了……但死的不是一个&#xff0c;而是两个。在这两集中&#xff0c;很多角色都遭遇过险境&…

php科学计数法转string,php如何将科学计数法转数字

php将科学计数法转数字的实现方法&#xff1a;首先通过if语句判断指定的数值是否为科学计数法&#xff1b;然后提取科学计数法中有效的数据&#xff1b;接着正式处理该数据&#xff1b;最后调用“convert_scientific_number_to_normal”方法实现转换即可。PHP将科学计数法转换为…

php8vsgo,服务端 I/O 性能:Node、PHP、Java、Go 的对比

原标题&#xff1a;服务端 I/O 性能&#xff1a;Node、PHP、Java、Go 的对比了解应用程序的输入/输出(I/O)模型意味着理解应用程序处理其数据的载入差异&#xff0c;并揭示其在真实环境中表现。或许你的应用程序很小&#xff0c;在不承受很大的负载时&#xff0c;这并不是个严重…

Python day8

阅读目录 为什么要用函数  函数的定义与调用  函数的返回值  函数的参数  本章小结返回顶部为什么要用函数 现在python届发生了一个大事件&#xff0c;len方法突然不能直接用了。。。 然后现在有一个需求&#xff0c;让你计算hello world的长度&#xff0c;你怎么计算&…

java创建对象过七夕,想 new 个对象过七夕,她却抛了异常

原标题&#xff1a;想 new 个对象过七夕&#xff0c;她却抛了异常关注 “”导读&#xff1a;单身之痛......作者 | 轩辕之风来源 | 编程技术宇宙(ID&#xff1a;xuanyuancoding)七夕又到了&#xff0c;单身汪们太难了&#xff0c;每年不仅要经历双十一&#xff0c;要经历2.14&a…

【Redis】解析Redis和Java传递数据

在Java中使用Redis之前需要导入 jedis.jar 包&#xff0c;由于Redis是基于key-value进行数据存储&#xff0c;java中的数据存储到Redis中有许多方式&#xff0c;这里笔者介绍采用JSON字符串和对象序列化两种方式。 1&#xff0c;使用JSON方式 首先将Java对象转化为JSON字符串 …

C#带按钮的文本框TextBoxContainButton

经常需要用到各种组合控件&#xff0c;每次组合太麻烦&#xff0c;通过打包成自定义控件&#xff0c;方便调用。 带按钮的文本框&#xff0c;如下图&#xff1a; 文本框内可以输入文本&#xff0c;响应文本框内容变化事件&#xff0c;按钮可以设置点击事件&#xff0c;图标 通过…

Windows单机配置Zookeeper环境

转自&#xff1a;http://www.jianshu.com/p/f7037105db46 首先要确保机器已经安装好java环境&#xff0c;并且配置好环境变量 http://apache.fayea.com/zookeeper/current/ 下载后&#xff0c;解压缩到硬盘&#xff0c;我这里解压到了 D:\WorkSoftware\zookeeper_3.4.9 解压缩在…

三层架构—简析

三层学习完了&#xff0c;第一次验收的时候&#xff0c;自己理解的也不是非常到位&#xff0c;后来又又一次敲了一遍登陆样例&#xff0c;查阅了一些资料 进行第二次验收才感觉清晰了很多。之前画时序图时我就想过时序图基本上也是非常好的体现了三层&#xff0c;当时也和别人讨…

机房收费系统之结账

其实&#xff0c;我认为机房收费系统中结账的部分是耗我精力最多的。首先我就不明确结账是干嘛的&#xff0c;所以一上来就晕乎乎。后来看了一篇博客说结账方便老板管理的才明确了为什么是“操作员”。这里面要理清的一点&#xff0c;结账的内容是未结账的。 暂时汇总的信息&am…