Default callback object design

No parameters are passed in , call add The function is changed to add To the interior list in , call fire It's triggered in sequence list The callback function in :

function fn1(val) {
console.log('fn1 says:' + val);
} function fn2(val) {
console.log('fn2 says ' + val);
}
var cbs = $.Callbacks();
cbs.add(fn1);
cbs.fire('foo');
console.log('........')
cbs.add(fn2);
cbs.fire('bar')

The result is stacking triggers in order , The following list :

fn1 says:foo
………………………
fn1 says:bar
fn2 says bar

This is the simplest way to deal with it , You can directly simulate , The code is as follows :

function Callbacks() {
var list = [];
var self;
self = {
add: function(fn) {
list.push(fn)
},
fire: function(args) {
list.forEach(function(fn) {
fn(args);
})
}
}
return self;
}

Code :

<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script src="http://img.mukewang.com/down/540812440001e40e00000000.js" type="text/javascript"></script>
<script src="http://img.mukewang.com/down/541f6ff70001a0a500000000.js" type="text/javascript"></script> <title></title>
</head>
<body> <script type="text/javascript"> function Callbacks() {
var list = [];
var self;
self = {
add: function(fn) {
list.push(fn)
},
fire: function(args) {
list.forEach(function(fn) {
fn(args);
})
}
}
return self;
} function fn1(val) {
show('fn1 says:' + val);
}
function fn2(val) {
show('fn2 says ' + val);
} var cbs = Callbacks();
cbs.add(fn1);
cbs.fire('foo');
cbs.add(fn2);
cbs.fire('bar') </script> </body>
</html>

once The design of the

once To ensure that the callback list only performs (.fire()) once ( Like a deferred Deferred), The following code :

function fn1(val){
console.log('fn1 says ' + val);
}
var cbs = $.Callbacks('once');
cbs.add(fn1);
cbs.fire('foo');
cbs.fire('foo');

As a result, you will find cbs.fire('foo') Only executed once .

fn1 says foo // Show only once

once The definition is very clear , Make sure that the callback list only performs ( .fire() ) once ( Like a deferred Deferred), So for this once There are many different ways to deal with .

1、add When you're in the middle of something

2、 stay fire When you're in the middle of something .

however jQuery It's performing the first fire I'm going to empty it when I'm going to list List. , And then in add Let's judge where we are list Whether there is , So as to achieve such a treatment .

function Callbacks(options) {
var list = [];
var self;
self = {
add: function(fn) {
list.push(fn)
},
fire: function(args) {
if (list) {
list.forEach(function(fn) {
fn(args);
})
if (options === 'once') {
list = undefined;
}
}
}
}
return self;
}

stay fire after , Judge whether the parameter is once, Put... Directly list Get rid of , So everything after that fire They're all abandoned , And from then on to once The effect of .

jQuery.Callbacks To deal with

stay fire Called in self.disable(); Method

// Disable callbacks in the callback list .
disable: function() {
list = stack = memory = undefined;
return this;
},

The sample code :

<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script src="http://img.mukewang.com/down/540812440001e40e00000000.js" type="text/javascript"></script>
<script src="http://img.mukewang.com/down/541f6ff70001a0a500000000.js" type="text/javascript"></script> <title></title>
</head>
<body> <script type="text/javascript"> function Callbacks(options) {
var list = [];
var self;
self = {
add: function(fn) {
list.push(fn)
},
fire: function(args) {
if(list){
list.forEach(function(fn) {
fn(args);
})
if(options === 'once'){
list = undefined;
}
}
}
}
return self;
} function fn1(val) {
show('fn1 says:' + val);
}
function fn2(val) {
show('fn2 says ' + val);
} var cbs = Callbacks('once');
cbs.add(fn1);
cbs.fire('foo');
cbs.fire('foo'); </script> </body>
</html>

memory The design of the

memory: Keep the previous value , The latest value added to the end of the list is immediately executed, calling any callback ( Like a deferred Deferred).

The callback function is from the asynchronous queue Deferred Separated from , So many interfaces are designed to fit Deferred Interface ,memory Use a lot of , The design of this cache is mentioned here

Mainly used to realize deferred Asynchronous collection and pipe Pipeline style data transmission , Specific in Deferred There is a detailed explanation , Here's a general idea of the scope of action .

memory This is a bit hard to understand , Let's explain it through Liezi , Look at the code below :

var cbs = Callbacks('once');
cbs.add(fn1);
cbs.fire('foo');
cbs.fire('foo'); function fn1(val) {
console.log('fn1 says ' + val);
}
function fn2(val) {
console.log('fn2 says ' + val);
}
function fn3(val) {
console.log('fn3 says ' + val);
} var cbs = $.Callbacks('memory');
cbs.add(fn1);
cbs.fire('foo'); console.log('..........') cbs.add(fn2);
cbs.fire('bar'); console.log('..........')
cbs.add(fn3);
cbs.fire('aaron');

It turns out that , We're executing cbs.add(fn2); When , At this point in addition to fn2 Added to the callback queue and immediately executed the method , The only difference is , The parameters are used before . So the explanation is called “ Keep the previous value ”.

fn1 says foo
..........
fn2 says foo
fn1 says bar
fn2 says bar
..........
fn3 says bar
fn1 says aaron
fn2 says aaron
fn3 says aaron

So this memory The problem that design needs to solve is :

1: How to get the last parameter

2:add How to carry out after

Look at the code we implemented :

function Callbacks(options) {
var list = [];
var self;
var firingStart;
var memory; function _fire(data) {
memory = options === 'memory' && data;
firingIndex = firingStart || 0;
firingStart = 0;
firingLength = list.length;
for (; list && firingIndex < firingLength; firingIndex++) {
list[firingIndex](data)
}
} self = {
add: function(fn) {
var start = list.length;
list.push(fn)
if (memory) {
firingStart = start; // Get the last value
_fire(memory);
}
},
fire: function(args) {
if (list) {
_fire(args)
}
}
}
return self;
}

First add After that, it should be able to trigger fire The action of , So we put fire As an internal private method implementation _fire, It's more logical , So the external fire It's just a facade method call .

Private variables memory Cache the properties of the last parameter , We depend on firingStart Used to locate and finally pass through add Added index of callback data . When traversing, it goes directly through firingStart The starting index location of , And then transfer memory Parameters of , And to achieve this “ Keep the previous value ” The design of the .

The sample code :

<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script src="http://img.mukewang.com/down/540812440001e40e00000000.js" type="text/javascript"></script>
<script src="http://img.mukewang.com/down/541f6ff70001a0a500000000.js" type="text/javascript"></script>
<title></title>
</head>
<body> <script type="text/javascript"> function Callbacks(options) {
var list = [];
var self;
var firingStart;
var memory; function _fire(data) {
memory = options === 'memory' && data;
firingIndex = firingStart || 0;
firingStart = 0;
firingLength = list.length;
for (; list && firingIndex < firingLength; firingIndex++) {
list[firingIndex](data)
}
} self = {
add: function(fn) {
var start = list.length;
list.push(fn)
if (memory) {
firingStart = start; // Get the last value
_fire(memory);
}
},
fire: function(args) {
if (list) {
_fire(args)
}
}
}
return self;
} function fn1(val) {
show('fn1 says ' + val);
} function fn2(val) {
show('fn2 says ' + val);
} function fn3(val) {
show('fn3 says ' + val);
} var cbs = Callbacks('memory');
cbs.add(fn1);
cbs.fire('foo'); cbs.add(fn2);
cbs.fire('bar'); cbs.add(fn3);
cbs.fire('aaron') </script> </body>
</html>

unique The design of the

Unique: Make sure that only one callback can be added at a time ( So there are no duplicate callbacks in the list )

function fn1(val) {
console.log('fn1 says ' + val);
}
var callbacks = $.Callbacks( "unique" );
callbacks.add( fn1 );
callbacks.add( fn1 ); // repeat addition
callbacks.add( fn1 );
callbacks.fire( "foo" );

result : Filtered the same add operation

fn1 says foo

It's easier to filter repetitions , Because it's the way arrays are saved , We can go through at the entrance indexOf Just judge

function Callbacks(options) {
var list = [];
var self;
var firingStart;
var memory; function _fire(data) {
memory = options === 'memory' && data;
firingIndex = firingStart || 0;
firingStart = 0;
firingLength = list.length;
for (; list && firingIndex < firingLength; firingIndex++) {
list[firingIndex](data)
}
} self = {
add: function(fn) {
var start = list.length;
if (options == 'unique') {
if (-1 === list.indexOf(fn)) {
list.push(fn)
}
} else {
list.push(fn)
}
if (memory) {
firingStart = start; // Get the last value
_fire(memory);
}
},
fire: function(args) {
if (list) {
_fire(args)
}
}
}
return self;
}

The sample code :

<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script src="http://img.mukewang.com/down/540812440001e40e00000000.js" type="text/javascript"></script>
<script src="http://img.mukewang.com/down/541f6ff70001a0a500000000.js" type="text/javascript"></script>
<title></title>
</head>
<body> <script type="text/javascript"> function Callbacks(options) {
var list = [];
var self;
var firingStart;
var memory; function _fire(data) {
memory = options === 'memory' && data;
firingIndex = firingStart || 0;
firingStart = 0;
firingLength = list.length;
for (; list && firingIndex < firingLength; firingIndex++) {
list[firingIndex](data)
}
} self = {
add: function(fn) {
var start = list.length;
if (options == 'unique') {
if (-1 === list.indexOf(fn)) {
list.push(fn)
}
} else {
list.push(fn)
}
if (memory) {
firingStart = start; // Get the last value
_fire(memory);
}
},
fire: function(args) {
if (list) {
_fire(args)
}
}
}
return self;
} function fn1(val) {
show('fn1 says ' + val);
}
var callbacks = Callbacks( "unique" );
callbacks.add( fn1 );
callbacks.add( fn1 ); // Add repeatedly
callbacks.add( fn1 );
callbacks.fire( "foo" ); </script> </body>
</html>

stopOnFalse

stopOnFalse: When a callback returns false Interrupt call when

function fn1(value) {
console.log(value);
return false;
} function fn2(value) {
fn1("fn2 says: " + value);
return false;
} var callbacks = $.Callbacks("stopOnFalse");
callbacks.add(fn1);
callbacks.fire("foo"); callbacks.add(fn2);
callbacks.fire("bar");

It turns out that fn1 Is added to the callback list , But because fn1 Back to false, Then the callback after the meaning will not be called . If there is fn3, stay f2 On the back false,fn3 And will not be called .

foo
bar

In this design, we only need to control the Boolean value returned by the function , This value is used to determine whether the next traversal is needed

if (list[firingIndex](data) === false && options === 'stopOnFalse') {
break;
}

Source code is as follows :

function Callbacks(options) {
var list = [];
var self;
var firingStart;
var memory; function _fire(data) {
memory = options === 'memory' && data;
firingIndex =
firingStart || 0;
firingStart = 0;
firingLength = list.length;
for (; list && firingIndex < firingLength; firingIndex++) {
if (list[firingIndex](data) === false && options === 'stopOnFalse') {
break;
}
}
} self = {
add: function(fn) {
var start = list.length;
if (options == 'unique') {
if (-1 === list.indexOf(fn)) {
list.push(fn)
}
} else {
list.push(fn)
}
if (memory) {
firingStart = start; // Get the last value
_fire(memory);
}
},
fire: function(args) {
if (list) {
_fire(args)
}
}
}
return self;
}

The above is the usage of several separate processing situations , We can see jQuery It's all in combination , The most common is

jQuery.Callbacks("once memory") A combination of , In fact, the above ideas have been explained , It's just that we should consider some judgments when we combine them .

Code example :

<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script src="http://img.mukewang.com/down/540812440001e40e00000000.js" type="text/javascript"></script>
<script src="http://img.mukewang.com/down/541f6ff70001a0a500000000.js" type="text/javascript"></script>
<title></title>
</head>
<body> <script type="text/javascript"> function Callbacks(options) {
var list = [];
var self;
var firingStart;
var memory; function _fire(data) {
memory = options === 'memory' && data;
firingIndex =
firingStart || 0;
firingStart = 0;
firingLength = list.length;
for (; list && firingIndex < firingLength; firingIndex++) {
if (list[firingIndex](data) === false && options === 'stopOnFalse') {
break;
}
}
} self = {
add: function(fn) {
var start = list.length;
if (options == 'unique') {
if (-1 === list.indexOf(fn)) {
list.push(fn)
}
} else {
list.push(fn)
}
if (memory) {
firingStart = start; // Get the last value
_fire(memory);
}
},
fire: function(args) {
if (list) {
_fire(args)
}
}
}
return self;
} function fn1( value ){
show( value );
return false;
} function fn2( value ){
fn1( "fn2 says: " + value );
return false;
} var callbacks = Callbacks('stopOnFalse');
callbacks.add(fn1);
callbacks.fire("foo1"); callbacks.add(fn2);
callbacks.fire("foo2"); </script> </body>
</html>

JQuery The source code parsing ( Ten ) More articles about

  1. JQuery The source code parsing ( One )

    Write it at the front : Ben <JQuery The source code parsing > The series is based on the articles of some predecessors for further analysis . elaboration . It's written out of modification , Thank you for your generous support of science popularization documents . To check JQ Please download the development version of JQ.j ...

  2. jQuery Source code analysis 2 :jQuery.fn.extend=jQuery.extend Methods to explore

    Finally, I started to write jQuery Source code analysis II , It's really difficult to write an article , Make clear what you understand , It's not easy to make people understand . stay  jQuery Source code analysis one :jQuery Class library overall architecture design analysis   One article , It gives a general description ...

  3. jquery The source code parsing : Code structure analysis

    This series is aimed at jquery2.0.3 Version of the explanation . This version does not support IE8 Up to . (function(){ (21, 94)     Some variables and functions are defined ,   jQuery = function() ...

  4. jquery The source code parsing

    Static and strength methods share design Traversal methods $(".a").each() // As an example, the method exists $.each() // As static methods exist Jquery Source code jQuery.prototype = ...

  5. jQuery Source code analysis resource note

    Recently began to interpret jQuery Source code , The links below are all searched , Of course, wonderful class   There's a series of Related videos , Long 100 Polyphase , It's like a snail crawling slowly , Read at least three frames , You can play strange in the future , Make your own wheels . Fully understand jQuery Original generation ...

  6. 3、 ... and .jQuery Source code analysis jQuery The frame diagram of

    This picture is right jQuery Source screenshot , A little bit of spelling . Now let's look at this picture jQuery I'm going to do a little bit of illustration . One .16~9404 OK, you can find , The outermost layer is a self calling function . When jQuery On initialization , This self calling function contains ...

  7. jquery The source code parsing :addClass,toggleClass,hasClass Detailed explanation

    This lesson , We will go on to explain jQuery Methods of manipulating element attributes . First , Let's take a look at how these methods are used : $("#div1").addClass("box1 box2&quo ...

  8. jquery The source code parsing :jQuery Detailed explanation of data caching mechanism 2

    Last lesson mainly talked about jQuery Caching mechanism in Data Source code analysis of construction method , This lesson is mainly about jQuery How to use Data Object to implement the static method and instance method of caching mechanism . Let's go on , Look at the source code solutions of these static methods and instance methods ...

  9. jquery The source code parsing :jQuery Detailed explanation of data caching mechanism 1

    jQuery There are three ways to add data in ,$().attr(),$().prop(),$().data(). But the first two are used to add attribute values to elements , Only for a small amount of data , such as :title,class,name etc. ...

  10. jquery The source code parsing :jQuery Tool method when Detailed explanation

    Let's see first when How is the method used : var cb = $.when();   //when Method also returns a deferred object , The source code is return deferred.promise(); The delay object returned cannot be modified ...

Random recommendation

  1. struts internationalization

    internationalization 1. Internationalization and localization internationalization (Internationalization: I18N): It's a program that doesn't make any changes , It can be used in different countries or regions and different language environments , Display according to local language and format habits ...

  2. Beta Project sprint &ndash; The fourth day

    Too many exams , Too little time for projects -- team :F4 member :031302301 Bi Rongjia 031302302 Cai Yixuan 031302430 Xiao Yang 031302418 Huang Yanning The content of the meeting : 1. Standing conference photos : 2. term ...

  3. OpenCV The road to growth 01、 Image reading, writing and display

    One . Tools section A good workman does his work well , You must sharpen your tools first . Study OpenCV, No less than basic programming tools and tools OpenCV library . stay Windows Under the platform, you can choose Visual Studio.CodeBlock etc. , Of course, you can also choose to be in Li ...

  4. HYSBZ 2440 Complete square ( Mobius inversion )

    link :http://www.lydsy.com/JudgeOnline/problem.php?id=2440 if i Prime number ,n by i*i Multiple , said n Is the number with square factor . seek 1~n The square free number of . F(x) ...

  5. Deepen understanding linux Under the last Commands and their data sources

    http://www.9usb.net/200902/linux-last.html http://blog.csdn.net/chaofanwei/article/details/11826567

  6. Garlic maker 444 / xtuoj 1024 Jingdong's logistics path ( Union checking set + offline lca) perhaps ( Point divide and conquer )

    The question : A tree , Define that the weight of a path is equal to the sum of the edge weights of the path , We need to find the maximum weight of all paths in this tree Ideas : Considering that the path weight is related to the maximum value of the point weight , And the most value problem can usually be handled by sorting , So I thought of sorting the points first . Easy to see, such as ...

  7. kvm Of live-snapshot

    The snapshot that already exists in the project is the snapshot for the volume , And need to shut down . So there are two needs at the moment :1. Don't shut down the snapshot :2. Snapshots for virtual machines , Not a snapshot of the coupons . By demand, so for libvirt Did some experiments , The record is as follows : Environmental Science : Physics ...

  8. RHEL Deploy ipa Red hat Authentication

    1. Download the package first yum install -y ipa-server bind bind-dyndb-ldap 2. initialization ipa Basic configuration ipa-server-install * Configure ...

  9. web 12

    Call a map ( Baidu Maps )API( location ) To website : 1. call API Of js : <script type="text/javascript" src="https:// ...

  10. VS add to WebService Tools

    I've been doing and WebService Related items , Because it's only used in school , It's never been used to work , So I'm not very familiar with , So I configured one myself WebService Tools have been added to VS(VisualStudio) Inside , In fact ...