您的位置:首页 > Web前端 > JavaScript

Understand JavaScript Callback Functions and Use Them-回调函数

2016-08-29 00:00 591 查看

(LearnJavaScriptHigher-orderFunctions,akaCallbackFunctions)

InJavaScript,functionsarefirst-classobjects;thatis,functionsareofthetypeObjectandtheycanbeusedinafirst-classmannerlikeanyotherobject(String,Array,Number,etc.)sincetheyareinfactobjectsthemselves.Theycanbe“storedinvariables,passedasargumentstofunctions,createdwithinfunctions,andreturnedfromfunctions”1.

OurCareerPathsandCoursesWebsiteIsNowLive

Learn.ModernDeveloperLaunched

Ourfirstcohortisinsession:97%ofourfirstcohortontargettograduate.Enrollinthesecondcohort.CareerPath1:JavaScriptDeveloperandCareerPath3:ModernFrontendDeveloperusuallyfillupquickly.

https://learn.moderndeveloper.com

TableofContents

OurCareerPathsandCoursesWebsiteIsNowLive

ReceiveUpdates

WhatisaCallbackorHigher-orderFunction?

HowCallbackFunctionsWork?

BasicPrincipleswhenImplementingCallbackFunctions

“CallbackHell”ProblemAndSolution

MakeYourOwnCallbackFunctions

FinalWords

ReceiveUpdates

Becausefunctionsarefirst-classobjects,wecanpassafunctionasanargumentinanotherfunctionandlaterexecutethatpassed-infunctionorevenreturnittobeexecutedlater.ThisistheessenceofusingcallbackfunctionsinJavaScript.IntherestofthisarticlewewilllearneverythingaboutJavaScriptcallbackfunctions.CallbackfunctionsareprobablythemostwidelyusedfunctionalprogrammingtechniqueinJavaScript,andyoucanfindtheminjustabouteverypieceofJavaScriptandjQuerycode,yettheyremainmysterioustomanyJavaScriptdevelopers.Themysterywillbenomore,bythetimeyoufinishreadingthisarticle.

Callbackfunctionsarederivedfromaprogrammingparadigmknownasfunctionalprogramming.Atafundamentallevel,functionalprogrammingspecifiestheuseoffunctionsasarguments.Functionalprogrammingwas—andstillis,thoughtoamuchlesserextenttoday—seenasanesoterictechniqueofspeciallytrained,masterprogrammers.

Fortunately,thetechniquesoffunctionalprogramminghavebeenelucidatedsothatmeremortalslikeyouandmecanunderstandandusethemwithease.Oneofthechieftechniquesinfunctionalprogramminghappenstobecallbackfunctions.Asyouwillreadshortly,implementingcallbackfunctionsisaseasyaspassingregularvariablesasarguments.ThistechniqueissosimplethatIwonderwhyitismostlycoveredinadvancedJavaScripttopics.

WhatisaCallbackorHigher-orderFunction?

Acallbackfunction,alsoknownasahigher-orderfunction,isafunctionthatispassedtoanotherfunction(let’scallthisotherfunction“otherFunction”)asaparameter,andthecallbackfunctioniscalled(orexecuted)insidetheotherFunction.Acallbackfunctionisessentiallyapattern(anestablishedsolutiontoacommonproblem),andtherefore,theuseofacallbackfunctionisalsoknownasacallbackpattern.

ConsiderthiscommonuseofacallbackfunctioninjQuery:


//Notethattheitemintheclickmethod'sparameterisafunction,notavariable.​
​//Theitemisacallbackfunction
$("#btn_1").click(function(){
alert("Btn1Clicked");
});
Asyouseeintheprecedingexample,wepassafunctionasaparametertotheclickmethod.Andtheclickmethodwillcall(orexecute)thecallbackfunctionwepassedtoit.ThisexampleillustratesatypicaluseofcallbackfunctionsinJavaScript,andonewidelyusedinjQuery.

RuminateonthisotherclassicexampleofcallbackfunctionsinbasicJavaScript:


varfriends=["Mike","Stacy","Andy","Rick"];
friends.forEach(function(eachName,index){
console.log(index+1+"."+eachName);//1.Mike,2.Stacy,3.Andy,4.Rick​
});
Again,notethewaywepassananonymousfunction(afunctionwithoutaname)totheforEachmethodasaparameter.

Sofarwehavepassedanonymousfunctionsasaparametertootherfunctionsormethods.Letsnowunderstandhowcallbacksworkbeforewelookatmoreconcreteexamplesandstartmakingourowncallbackfunctions.

HowCallbackFunctionsWork?

Wecanpassfunctionsaroundlikevariablesandreturntheminfunctionsandusetheminotherfunctions.Whenwepassacallbackfunctionasanargumenttoanotherfunction,weareonlypassingthefunctiondefinition.Wearenotexecutingthefunctionintheparameter.Inotherwords,wearen’tpassingthefunctionwiththetrailingpairofexecutingparenthesis()likewedowhenweareexecutingafunction.

Andsincethecontainingfunctionhasthecallbackfunctioninitsparameterasafunctiondefinition,itcanexecutethecallbackanytime.

Notethatthecallbackfunctionisnotexecutedimmediately.Itis“calledback”(hencethename)atsomespecifiedpointinsidethecontainingfunction’sbody.So,eventhoughthefirstjQueryexamplelookedlikethis:


//Theanonymousfunctionisnotbeingexecutedthereintheparameter.​
​//Theitemisacallbackfunction
$("#btn_1").click(function(){
alert("Btn1Clicked");
});
theanonymousfunctionwillbecalledlaterinsidethefunctionbody.Evenwithoutaname,itcanstillbeaccessedlaterviatheargumentsobjectbythecontainingfunction.

CallbackFunctionsAreClosures
Whenwepassacallbackfunctionasanargumenttoanotherfunction,thecallbackisexecutedatsomepointinsidethecontainingfunction’sbodyjustasifthecallbackweredefinedinthecontainingfunction.Thismeansthecallbackisaclosure.Readmypost,UnderstandJavaScriptClosuresWithEaseformoreonclosures.Asweknow,closureshaveaccesstothecontainingfunction’sscope,sothecallbackfunctioncanaccessthecontainingfunctions’variables,andeventhevariablesfromtheglobalscope.

BasicPrincipleswhenImplementingCallbackFunctions

Whileuncomplicated,callbackfunctionshaveafewnoteworthyprinciplesweshouldbefamiliarwithwhenimplementingthem.

UseNamedORAnonymousFunctionsasCallbacks
IntheearlierjQueryandforEachexamples,weusedanonymousfunctionsthatweredefinedintheparameterofthecontainingfunction.Thatisoneofthecommonpatternsforusingcallbackfunctions.Anotherpopularpatternistodeclareanamedfunctionandpassthenameofthatfunctiontotheparameter.Considerthis:



//globalvariable​
​varallUserData=[];
​//genericlogStufffunctionthatprintstoconsole​
​functionlogStuff(userData){
if(typeofuserData==="string")
{
console.log(userData);
}
elseif(typeofuserData==="object")
{
for(variteminuserData){
console.log(item+":"+userData[item]);
}
}
}
​//Afunctionthattakestwoparameters,thelastoneacallbackfunction​
​functiongetInput(options,callback){
allUserData.push(options);
callback(options);
}
​//WhenwecallthegetInputfunction,wepasslogStuffasaparameter.​
​//SologStuffwillbethefunctionthatwillcalledback(orexecuted)insidethegetInputfunction​
getInput({name:"Rich",speciality:"JavaScript"},logStuff);
​//name:Rich​
​//speciality:JavaScript
PassParameterstoCallbackFunctions
Sincethecallbackfunctionisjustanormalfunctionwhenitisexecuted,wecanpassparameterstoit.Wecanpassanyofthecontainingfunction’sproperties(orglobalproperties)asparameterstothecallbackfunction.Intheprecedingexample,wepassoptionsasaparametertothecallbackfunction.Let’spassaglobalvariableandalocalvariable:


//Globalvariable​
​vargeneralLastName="Clinton";
​functiongetInput(options,callback){
allUserData.push(options);
​//PasstheglobalvariablegeneralLastNametothecallbackfunction​
callback(generalLastName,options);
}
MakeSureCallbackisaFunctionBeforeExecutingIt
Itisalwayswisetocheckthatthecallbackfunctionpassedintheparameterisindeedafunctionbeforecallingit.Also,itisgoodpracticetomakethecallbackfunctionoptional.

Let’srefactorthegetInputfunctionfromthepreviousexampletoensurethesechecksareinplace.


functiongetInput(options,callback){
allUserData.push(options);
//Makesurethecallbackisafunction​
if(typeofcallback==="function"){
//Callit,sincewehaveconfirmeditiscallable​
callback(options);
}
}
Withoutthecheckinplace,ifthegetInputfunctioniscalledeitherwithoutthecallbackfunctionasaparameterorinplaceofafunctionanon-functionispassed,ourcodewillresultinaruntimeerror.

ProblemWhenUsingMethodsWithThethisObjectasCallbacks
Whenthecallbackfunctionisamethodthatusesthethisobject,wehavetomodifyhowweexecutethecallbackfunctiontopreservethethisobjectcontext.Orelsethethisobjectwilleitherpointtotheglobalwindowobject(inthebrowser),ifcallbackwaspassedtoaglobalfunction.Oritwillpointtotheobjectofthecontainingmethod.
Let’sexplorethisincode:



//Defineanobjectwithsomepropertiesandamethod​
​//Wewilllaterpassthemethodasacallbackfunctiontoanotherfunction​
​varclientData={
id:094545,
fullName:"NotSet",
//setUserNameisamethodontheclientDataobject​
setUserName:function(firstName,lastName){
//thisreferstothefullNamepropertyinthisobject​
this.fullName=firstName+""+lastName;
}
}
​functiongetUserInput(firstName,lastName,callback){
//DootherstufftovalidatefirstName/lastNamehere​
//Nowsavethenames​
callback(firstName,lastName);
}
Inthefollowingcodeexample,whenclientData.setUserNameisexecuted,this.fullNamewillnotsetthefullNamepropertyontheclientDataobject.Instead,itwillsetfullNameonthewindowobject,sincegetUserInputisaglobalfunction.Thishappensbecausethethisobjectintheglobalfunctionpointstothewindowobject.


getUserInput("Barack","Obama",clientData.setUserName);
console.log(clientData.fullName);//NotSet​
​//ThefullNamepropertywasinitializedonthewindowobject​
console.log(window.fullName);//BarackObama
UsetheCallorApplyFunctionToPreservethis
WecanfixtheprecedingproblembyusingtheCallorApplyfunction(wewilldiscusstheseinafullblogpostlater).Fornow,knowthateveryfunctioninJavaScripthastwomethods:CallandApply.Andthesemethodsareusedtosetthethisobjectinsidethefunctionandtopassargumentstothefunctions.

Calltakesthevaluetobeusedasthethisobjectinsidethefunctionasthefirstparameter,andtheremainingargumentstobepassedtothefunctionarepassedindividually(separatedbycommasofcourse).TheApplyfunction’sfirstparameterisalsothevaluetobeusedasthethisobjectinsidethefunction,whilethelastparameterisanarrayofvalues(ortheargumentsobject)topasstothefunction.

Thissoundscomplex,butletsseehoweasyitistouseApplyorCall.Tofixtheprobleminthepreviousexample,wewillusetheApplyfunctionthus:


//Notethatwehaveaddedanextraparameterforthecallbackobject,called"callbackObj"​
​functiongetUserInput(firstName,lastName,callback,callbackObj){
//Dootherstufftovalidatenamehere​
//TheuseoftheApplyfunctionbelowwillsetthethisobjecttobecallbackObj​
callback.apply(callbackObj,[firstName,lastName]);
}
WiththeApplyfunctionsettingthethisobjectcorrectly,wecannowcorrectlyexecutethecallbackandhaveitsetthefullNamepropertycorrectlyontheclientDataobject:


//WepasstheclientData.setUserNamemethodandtheclientDataobjectasparameters.TheclientDataobjectwillbeusedbytheApplyfunctiontosetthethisobject​

getUserInput("Barack","Obama",clientData.setUserName,clientData);
​//thefullNamepropertyontheclientDatawascorrectlyset​
console.log(clientData.fullName);//BarackObama
WewouldhavealsousedtheCallfunction,butinthiscaseweusedtheApplyfunction.

MultipleCallbackFunctionsAllowed
Wecanpassmorethanonecallbackfunctionsintotheparameterofafunction,justlikewecanpassmorethanonevariable.HereisaclassicexamplewithjQuery’sAJAXfunction:


functionsuccessCallback(){
//Dostuffbeforesend​
}
​functionsuccessCallback(){
//Dostuffifsuccessmessagereceived​
}
​functioncompleteCallback(){
//Dostuffuponcompletion​
}
​functionerrorCallback(){
//Dostuffiferrorreceived​
}
$.ajax({
url:"http://fiddle.jshell.net/favicon.png",
success:successCallback,
complete:completeCallback,
error:errorCallback
});

“CallbackHell”ProblemAndSolution

Inasynchronouscodeexecution,whichissimplyexecutionofcodeinanyorder,sometimesitiscommontohavenumerouslevelsofcallbackfunctionstotheextentthatyouhavecodethatlookslikethefollowing.Themessycodebelowiscalledcallbackhellbecauseofthedifficultyoffollowingthecodeduetothemanycallbacks.Itookthisexamplefromthenode-mongodb-native,aMongoDBdriverforNode.js.[2].Theexamplecodebelowisjustfordemonstration:


varp_client=newDb('integration_tests_20',newServer("127.0.0.1",27017,{}),{'pk':CustomPKFactory});
p_client.open(function(err,p_client){
p_client.dropDatabase(function(err,done){
p_client.createCollection('test_custom_key',function(err,collection){
collection.insert({'a':1},function(err,docs){
collection.find({'_id':newObjectID("aaaaaaaaaaaa")},function(err,cursor){
cursor.toArray(function(err,items){
test.assertEquals(1,items.length);
//Let'sclosethedb​
p_client.close();
});
});
});
});
});
});
Youarenotlikelytoencounterthisproblemofteninyourcode,butwhenyoudo—andyouwillfromtimetotime—herearetwosolutionstothisproblem.[3]





Nameyourfunctionsanddeclarethemandpassjustthenameofthefunctionasthecallback,insteadofdefiningananonymousfunctionintheparameterofthemainfunction.

Modularity:Separateyourcodeintomodules,soyoucanexportasectionofcodethatdoesaparticularjob.Thenyoucanimportthatmoduleintoyourlargerapplication.

MakeYourOwnCallbackFunctions

Nowthatyoucompletely(Ithinkyoudo;ifnotitisaquickreread:))understandeverythingaboutJavaScriptcallbackfunctionsandyouhaveseenthatusingcallbackfunctionsarerathersimpleyetpowerful,youshouldlookatyourowncodeforopportunitiestousecallbackfunctions,fortheywillallowyouto:

Donotrepeatcode(DRY—DoNotRepeatYourself)

Implementbetterabstractionwhereyoucanhavemoregenericfunctionsthatareversatile(canhandleallsortsoffunctionalities)

Havebettermaintainability

Havemorereadablecode

Havemorespecializedfunctions.

Itisrathereasytomakeyourowncallbackfunctions.Inthefollowingexample,Icouldhavecreatedonefunctiontodoallthework:retrievetheuserdata,createagenericpoemwiththedata,andgreettheuser.Thiswouldhavebeenamessyfunctionwithmuchif/elsestatementsand,evenstill,itwouldhavebeenverylimitedandincapableofcarryingoutotherfunctionalitiestheapplicationmightneedwiththeuserdata.

Instead,Ilefttheimplementationforaddedfunctionalityuptothecallbackfunctions,sothatthemainfunctionthatretrievestheuserdatacanperformvirtuallyanytaskwiththeuserdatabysimplypassingtheuser’sfullnameandgenderasparameterstothecallbackfunctionandthenexecutingthecallbackfunction.

Inshort,thegetUserInputfunctionisversatile:itcanexecuteallsortsofcallbackfunctionswithmyriadoffunctionalities.


//First,setupthegenericpoemcreatorfunction;itwillbethecallbackfunctioninthegetUserInputfunctionbelow.​
​functiongenericPoemMaker(name,gender){
console.log(name+"isfinerthanfinewine.");
console.log("Altruisticandnobleforthemoderntime.");
console.log("Alwaysadmirablyadornedwiththelateststyle.");
console.log("A"+gender+"ofunfortunatetragedieswhostillmanagesaperpetualsmile");
}
​//Thecallback,whichisthelastitemintheparameter,willbeourgenericPoemMakerfunctionwedefinedabove.​
​functiongetUserInput(firstName,lastName,gender,callback){
varfullName=firstName+""+lastName;
//Makesurethecallbackisafunction​
if(typeofcallback==="function"){
//Executethecallbackfunctionandpasstheparameterstoit​
callback(fullName,gender);
}
}
CallthegetUserInputfunctionandpassthegenericPoemMakerfunctionasacallback:


getUserInput("Michael","Fassbender","Man",genericPoemMaker);
​//Output​
​/*MichaelFassbenderisfinerthanfinewine.
Altruisticandnobleforthemoderntime.
Alwaysadmirablyadornedwiththelateststyle.
AManofunfortunatetragedieswhostillmanagesaperpetualsmile.
*/
BecausethegetUserInputfunctionisonlyhandlingtheretrievingofdata,wecanpassanycallbacktoit.Forexample,wecanpassagreetUserfunctionlikethis:


functiongreetUser(customerName,sex){
varsalutation=sex&&sex==="Man"?"Mr.":"Ms.";
console.log("Hello,"+salutation+""+customerName);
}
​//PassthegreetUserfunctionasacallbacktogetUserInput​
​getUserInput("Bill","Gates","Man",greetUser);
​//Andthisistheoutput​
Hello,Mr.BillGates
WecalledthesamegetUserInputfunctionaswedidbefore,butthistimeitperformedacompletelydifferenttask.

Asyousee,callbackfunctionsaffordmuchversatility.Andeventhoughtheprecedingexampleisrelativelysimple,imaginehowmuchworkyoucansaveyourselfandhowwellabstractedyourcodewillbeifyoustartusingcallbackfunctions.Goforit.Doitinthemonings;doitintheevenings;doitwhenyouaredown;doitwhenyouarek

NotethefollowingwayswefrequentlyusecallbackfunctionsinJavaScript,especiallyinmodernwebapplicationdevelopment,inlibraries,andinframeworks:


Forasynchronousexecution(suchasreadingfiles,andmakingHTTPrequests)

InEventListeners/Handlers

InsetTimeoutandsetIntervalmethods

ForGeneralization:codeconciseness

FinalWords

JavaScriptcallbackfunctionsarewonderfulandpowerfultouseandtheyprovidegreatbenefitstoyourwebapplicationsandcode.Youshouldusethemwhentheneedarises;lookforwaystorefactoryourcodeforAbstraction,Maintainability,andReadabilitywithcallbackfunctions.

Seeyounexttime,andremembertokeepcomingbackbecauseJavaScriptIsSexy.comhasmuchtoteachyouandyouhavemuchtolearn.

Notes

http://c2.com/cgi/wiki?FirstClass

https://github.com/mongodb/node-mongodb-native

http://callbackhell.com/

JavaScriptPatterns

byStoyanStefanov(Sep28,2010)

Postedin:16ImportantJavaScriptConcepts,AdvancedjavaScript,JavaScript/Tagged:CallbackFunctions,Higher-orderFunctions

RichardThanksforyourtime;pleasecomebacksoon.Emailmehere:javascriptissexyatgmailemail,orusethecontactform.
http://javascriptissexy.com/understand-javascript-callback-functions-and-use-them/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  javascript callback 回调