JavaScriptµÄÓÅÊÆÖ®Ò»ÊÇÆäÈçºÎ´¦ÀíÒì²½´úÂë¡£Òì²½´úÂë»á±»·ÅÈëÒ»¸öʼþ¶ÓÁУ¬µÈµ½ËùÓÐÆäËû´úÂëÖ´Ðкó²Å½øÐУ¬¶ø²»»á×èÈûÏ̡߳£È»¶ø£¬¶ÔÓÚ³õѧÕßÀ´Ëµ£¬ÊéдÒì²½´úÂë¿ÉÄÜ»á±È½ÏÀ§ÄÑ¡£¶øÔÚÕâƪÎÄÕÂÀÎÒ½«»áÏû³ýÄã¿ÉÄÜ»áÓеÄÈκÎÀ§»ó¡£
Àí½âÒì²½´úÂë
JavaScript×î»ù´¡µÄÒì²½º¯ÊýÊÇsetTimeoutºÍsetInterval¡£setTimeout»áÔÚÒ»¶¨Ê±¼äºóÖ´Ðиø¶¨µÄº¯Êý¡£Ëü½ÓÊÜÒ»¸ö»Øµ÷º¯Êý×÷ΪµÚÒ»²ÎÊýºÍÒ»¸öºÁÃëʱ¼ä×÷ΪµÚ¶þ²ÎÊý¡£ÒÔÏÂÊÇÓ÷¨¾ÙÀý£º
- console.log( "a" );
- setTimeout(function() {
- console.log( "c" )
- }, 500 );
- setTimeout(function() {
- console.log( "d" )
- }, 500 );
- setTimeout(function() {
- console.log( "e" )
- }, 500 );
- console.log( "b" );
ÕýÈçÔ¤ÆÚ£¬¿ØÖÆ̨ÏÈÊä³ö“a”¡¢“b”£¬´óÔ¼500ºÁÃëºó£¬ÔÙ¿´µ½“c”¡¢“d”¡¢“e”¡£ÎÒÓÓ´óÔ¼”ÊÇÒòΪsetTimeoutÊÂʵÉÏÊDz»¿ÉÔ¤ÖªµÄ¡£Êµ¼ÊÉÏ£¬ÉõÖÁ HTML5¹æ·¶¶¼Ìáµ½ÁËÕâ¸öÎÊÌ⣺
“Õâ¸öAPI²»Äܱ£Ö¤¼Æʱ»áÈçÆÚ׼ȷµØÔËÐС£ÓÉÓÚCPU¸ºÔØ¡¢ÆäËûÈÎÎñµÈËùµ¼ÖµÄÑÓ³ÙÊÇ¿ÉÒÔÔ¤Áϵ½µÄ¡£” |
ÓÐȤµÄÊÇ£¬Ö±µ½ÔÚͬһ³ÌÐò¶ÎÖÐËùÓÐÆäÓàµÄ´úÂëÖ´ÐнáÊøºó£¬³¬Ê±²Å»á·¢Éú¡£ËùÒÔÈç¹ûÉèÖÃÁ˳¬Ê±£¬Í¬Ê±Ö´ÐÐÁËÐ賤ʱ¼äÔËÐеĺ¯Êý£¬ÄÇôÔڸú¯ÊýÖ´ÐÐÍê³É֮ǰ£¬³¬Ê±ÉõÖÁ¶¼²»»áÆô¶¯¡£Êµ¼ÊÉÏ£¬Òì²½º¯Êý£¬ÈçsetTimeoutºÍsetInterval£¬±»Ñ¹ÈëÁ˳Æ֮ΪEvent LoopµÄ¶ÓÁС£
Event LoopÊÇÒ»¸ö»Øµ÷º¯Êý¶ÓÁС£µ±Òì²½º¯ÊýÖ´ÐÐʱ£¬»Øµ÷º¯Êý»á±»Ñ¹ÈëÕâ¸ö¶ÓÁС£JavaScriptÒýÇæÖ±µ½Òì²½º¯ÊýÖ´ÐÐÍê³Éºó£¬²Å»á¿ªÊ¼´¦ÀíʼþÑ»·¡£ÕâÒâζ×ÅJavaScript´úÂë²»ÊǶàÏ̵߳ģ¬¼´Ê¹±íÏÖµÄÐÐΪÏàËÆ¡£Ê¼þÑ»·ÊÇÒ»¸öÏȽøÏȳö£¨FIFO£©¶ÓÁУ¬Õâ˵Ã÷»Øµ÷ÊÇ°´ÕÕËüÃDZ»¼ÓÈë¶ÓÁеÄ˳ÐòÖ´Ðеġ£JavaScript±» nodeÑ¡×öΪ¿ª·¢ÓïÑÔ£¬¾ÍÊÇÒòΪдÕâÑùµÄ´úÂë¶àô¼òµ¥°¡¡£
Ajax
Òì²½JavascriptÓëXML£¨AJAX£©ÓÀ¾ÃÐԵĸıäÁËJavascriptÓïÑÔµÄ×´¿ö¡£Í»È»¼ä£¬ä¯ÀÀÆ÷²»ÔÙÐèÒªÖØмÓÔؼ´¿É¸üÐÂwebÒ³Ãæ¡£ ÔÚ²»Í¬µÄä¯ÀÀÆ÷ÖÐʵÏÖAjaxµÄ´úÂë¿ÉÄÜÂþ³¤²¢ÇÒ·¦Î¶£»µ«ÊÇ£¬ÐÒ¿÷ÓÐjQuery£¨»¹ÓÐÆäËû¿â£©µÄ°ïÖú£¬ÎÒÃÇÄܹ»ÒÔºÜÈÝÒײ¢ÇÒÓÅÑŵķ½Ê½ÊµÏÖ¿Í»§¶Ë-·þÎñÆ÷¶ËͨѶ¡£
ÎÒÃÇ¿ÉÒÔʹÓÃjQuery¿çä¯ÀÀÆ÷½Ó¿Ú$.ajaxºÜÈÝÒ׵ؼìË÷Êý¾Ý£¬È»¶øÈ´²»ÄܳÊÏÖÄ»ºó·¢ÉúÁËʲô¡£±ÈÈ磺
- var data;
- $.ajax({
- url: "some/url/1",
- success: function( data ) {
- // But, this will!
- console.log( data );
- }
- })
- // Oops, this won't work...
- console.log( data );
½ÏÈÝÒ×·¸µÄ´íÎó£¬ÊÇÔÚµ÷ÓÃ$.ajaxÖ®ºóÂíÉÏʹÓÃdata£¬µ«ÊÇʵ¼ÊÉÏÊÇÕâÑùµÄ£º
- xmlhttp.open( "GET", "some/ur/1", true );
- xmlhttp.onreadystatechange = function( data ) {
- if ( xmlhttp.readyState === 4 ) {
- console.log( data );
- }
- };
- xmlhttp.send( null );
µ×²ãµÄXmlHttpRequest¶ÔÏó·¢ÆðÇëÇó£¬ÉèÖûص÷º¯ÊýÓÃÀ´´¦ÀíXHRµÄreadystatechnageʼþ¡£È»ºóÖ´ÐÐXHRµÄsend·½·¨¡£ÔÚXHRÔËÐÐÖУ¬µ±ÆäÊôÐÔreadyState¸Ä±äʱreadystatechangeʼþ¾Í»á±»´¥·¢£¬Ö»ÓÐÔÚXHR´ÓÔ¶¶Ë·þÎñÆ÷½ÓÊÕÏìÓ¦½áÊøʱ»Øµ÷º¯Êý²Å»á´¥·¢Ö´ÐС£
´¦ÀíÒì²½´úÂë
Òì²½±à³ÌºÜÈÝÒ×ÏÝÈëÎÒÃdz£ËµµÄ“»Øµ÷µØÓü”¡£ÒòΪÊÂʵÉϼ¸ºõJSÖеÄËùÓÐÒì²½º¯Êý¶¼Óõ½Á˻ص÷£¬Á¬ÐøÖ´Ðм¸¸öÒì²½º¯ÊýµÄ½á¹û¾ÍÊDzã²ãǶÌ׵Ļص÷º¯ÊýÒÔ¼°ËæÖ®¶øÀ´µÄ¸´ÔÓ´úÂë¡£
node.jsÖеÄÐí¶àº¯ÊýÒ²ÊÇÒì²½µÄ¡£Òò´ËÈçϵĴúÂë»ù±¾ÉϺܳ£¼û£º
- var fs = require( "fs" );
- fs.exists( "index.js", function() {
- fs.readFile( "index.js", "utf8", function( err, contents ) {
- contents = someFunction( contents ); // do something with contents
- fs.writeFile( "index.js", "utf8", function() {
- console.log( "whew! Done finally..." );
- });
- });
- });
- console.log( "executing..." );
ÏÂÃæµÄ¿Í»§¶Ë´úÂëÒ²ºÜ¶à¼û£º
- GMaps.geocode({
- address: fromAddress,
- callback: function( results, status ) {
- if ( status == "OK" ) {
- fromLatLng = results[0].geometry.location;
- GMaps.geocode({
- address: toAddress,
- callback: function( results, status ) {
- if ( status == "OK" ) {
- toLatLng = results[0].geometry.location;
- map.getRoutes({
- origin: [ fromLatLng.lat(), fromLatLng.lng() ],
- destination: [ toLatLng.lat(), toLatLng.lng() ],
- travelMode: "driving",
- unitSystem: "imperial",
- callback: function( e ){
- console.log( "ANNNND FINALLY here's the directions..." );
- // do something with e
- }
- });
- }
- }
- });
- }
- }
- });
Nested callbacks can get really nasty, but there are several solutions to this style of coding.
ǶÌ׵Ļص÷ºÜÈÝÒ×´øÀ´´úÂëÖеē»µÎ¶µÀ”£¬²»¹ýÄã¿ÉÒÔÓÃÒÔϵļ¸ÖÖ·ç¸ñÀ´³¢ÊÔ½â¾öÕâ¸öÎÊÌâ
The problem isn’t with the language itself; it’s with the way programmers use the language — Async Javascript.
ûÓÐÔã¸âµÄÓïÑÔ£¬Ö»ÓÐÔã¸âµÄ³ÌÐòÔ³ ——Òì²½JavaSript |
ÃüÃûº¯Êý
Çå³ýǶÌ׻ص÷µÄÒ»¸ö±ã½ÝµÄ½â¾ö·½°¸ÊǼòµ¥µÄ±ÜÃâË«²ãÒÔÉϵÄǶÌס£´«µÝÒ»¸öÃüÃûº¯Êý¸ø×÷Ϊ»Øµ÷²ÎÊý£¬¶ø²»ÊÇ´«µÝÄäÃûº¯Êý£º
- var fromLatLng, toLatLng;
- var routeDone = function( e ){
- console.log( "ANNNND FINALLY here's the directions..." );
- // do something with e
- };
- var toAddressDone = function( results, status ) {
- if ( status == "OK" ) {
- toLatLng = results[0].geometry.location;
- map.getRoutes({
- origin: [ fromLatLng.lat(), fromLatLng.lng() ],
- destination: [ toLatLng.lat(), toLatLng.lng() ],
- travelMode: "driving",
- unitSystem: "imperial",
- callback: routeDone
- });
- }
- };
- var fromAddressDone = function( results, status ) {
- if ( status == "OK" ) {
- fromLatLng = results[0].geometry.location;
- GMaps.geocode({
- address: toAddress,
- callback: toAddressDone
- });
- }
- };
- GMaps.geocode({
- address: fromAddress,
- callback: fromAddressDone
- });
´ËÍâ, async.js ¿â¿ÉÒÔ°ïÖúÎÒÃÇ´¦Àí¶àÖØAjax requests/responses. ÀýÈ磺
- async.parallel([
- function( done ) {
- GMaps.geocode({
- address: toAddress,
- callback: function( result ) {
- done( null, result );
- }
- });
- },
- function( done ) {
- GMaps.geocode({
- address: fromAddress,
- callback: function( result ) {
- done( null, result );
- }
- });
- }
- ], function( errors, results ) {
- getRoute( results[0], results[1] );
- });
Õâ¶Î´úÂëÖ´ÐÐÁ½¸öÒì²½º¯Êý£¬Ã¿¸öº¯Êý¶¼½ÓÊÕÒ»¸öÃûΪ"done"µÄ»Øµ÷º¯Êý²¢ÔÚº¯Êý½áÊøµÄʱºòµ÷ÓÃËü¡£µ±Á½¸ö"done"»Øµ÷º¯Êý½áÊøºó£¬parallelº¯ÊýµÄ»Øµ÷º¯Êý±»µ÷Óò¢Ö´Ðлò´¦ÀíÕâÁ½¸öÒì²½º¯Êý²úÉúµÄ½á¹û»ò´íÎó¡£
PromisesÄ£ÐÍ
Òý×Ô CommonJS/A£º
promise±íʾһ¸ö²Ù×÷¶ÀÁ¢Íê³Éºó·µ»ØµÄ×îÖÕ½á¹û¡£ |
Óкܶà¿â¶¼°üº¬ÁËpromiseÄ£ÐÍ£¬ÆäÖÐjQueryÒѾÓÐÁËÒ»¸ö¿ÉʹÓÃÇҺܳöÉ«µÄpromise API¡£jQueryÔÚ1.5°æ±¾ÒýÈëÁËDeferred¶ÔÏ󣬲¢¿ÉÒÔÔÚ·µ»ØpromiseµÄº¯ÊýÖÐʹÓÃjQuery.DeferredµÄ¹¹Ôì½á¹û¡£¶ø·µ»ØpromiseµÄº¯ÊýÔòÓÃÓÚÖ´ÐÐijÖÖÒì²½²Ù×÷²¢½â¾öÍê³ÉºóµÄÑÓ³Ù¡£
- var geocode = function( address ) {
- var dfd = new $.Deferred();
- GMaps.geocode({
- address: address,
- callback: function( response, status ) {
- return dfd.resolve( response );
- }
- });
- return dfd.promise();
- };
- var getRoute = function( fromLatLng, toLatLng ) {
- var dfd = new $.Deferred();
- map.getRoutes({
- origin: [ fromLatLng.lat(), fromLatLng.lng() ],
- destination: [ toLatLng.lat(), toLatLng.lng() ],
- travelMode: "driving",
- unitSystem: "imperial",
- callback: function( e ) {
- return dfd.resolve( e );
- }
- });
- return dfd.promise();
- };
- var doSomethingCoolWithDirections = function( route ) {
- // do something with route
- };
- $.when( geocode( fromAddress ), geocode( toAddress ) ).
- then(function( fromLatLng, toLatLng ) {
- getRoute( fromLatLng, toLatLng ).then( doSomethingCoolWithDirections );
- });
ÕâÔÊÐíÄãÖ´ÐÐÁ½¸öÒì²½º¯Êýºó£¬µÈ´ýËüÃǵĽá¹û£¬Ö®ºóÔÙÓÃÏÈÇ°Á½¸öµ÷ÓõĽá¹ûÀ´Ö´ÐÐÁíÍâÒ»¸öº¯Êý¡£
promise±íʾһ¸ö²Ù×÷¶ÀÁ¢Íê³Éºó·µ»ØµÄ×îÖÕ½á¹û¡£ |
ÔÚÕâ¶Î´úÂëÀgeocode·½·¨Ö´ÐÐÁËÁ½´Î²¢·µ»ØÁËÒ»¸öpromise¡£Òì²½º¯ÊýÖ®ºóÖ´ÐУ¬²¢ÔÚÆä»Øµ÷Àïµ÷ÓÃÁËresolve¡£È»ºó£¬Ò»µ©Á½´Îµ÷ÓÃresolveÍê³É£¬then½«»áÖ´ÐУ¬Æä½ÓÊÕÁË֮ǰÁ½´Îµ÷ÓÃgeocodeµÄ·µ»Ø½á¹û¡£½á¹ûÖ®ºó±»´«ÈëgetRoute£¬´Ë·½·¨Ò²·µ»ØÒ»¸öpromise¡£×îÖÕ£¬µ±getRouteµÄpromise½â¾öºó£¬doSomethingCoolWithDirections»Øµ÷¾ÍÖ´ÐÐÁË¡£
ʼþ
ʼþÊÇÁíÒ»ÖÖµ±Òì²½»Øµ÷Íê³É´¦ÀíºóµÄͨѶ·½Ê½¡£Ò»¸ö¶ÔÏó¿ÉÒÔ³ÉΪ·¢ÉäÆ÷²¢ÅÉ·¢Ê¼þ£¬¶øÁíÍâµÄ¶ÔÏóÔò¼àÌýÕâЩʼþ¡£ÕâÖÖÀàÐ͵Äʼþ´¦Àí·½Ê½³Æ֮Ϊ ¹Û²ìÕßģʽ ¡£ backbone.js ¿âÔÚwithBackbone.EventsÖоʹ´½¨ÁËÕâÑùµÄ¹¦ÄÜÄ£¿é¡£
- var SomeModel = Backbone.Model.extend({
- url: "/someurl"
- });
- var SomeView = Backbone.View.extend({
- initialize: function() {
- this.model.on( "reset", this.render, this );
- this.model.fetch();
- },
- render: function( data ) {
- // do something with data
- }
- });
- var view = new SomeView({
- model: new SomeModel()
- });
»¹ÓÐÆäËûÓÃÓÚ·¢ÉäʼþµÄ»ìºÏÀý×Ӻͺ¯Êý¿â£¬ÀýÈç jQuery Event Emitter £¬ EventEmitter £¬ monologue.js £¬ÒÔ¼°node.jsÄÚ½¨µÄ EventEmitter Ä£¿é¡£
ʼþÑ»·ÊÇÒ»¸ö»Øµ÷º¯ÊýµÄ¶ÓÁС£ |
Ò»¸öÀàËƵÄÅÉ·¢ÏûÏ¢µÄ·½Ê½³ÆΪ ÖнéÕßģʽ £¬ postal.js ¿âÖÐÓõļ´ÊÇÕâÖÖ·½Ê½¡£ÔÚÖнéÕßģʽ£¬ÓÐÒ»¸öÓÃÓÚËùÓжÔÏó¼àÌýºÍÅÉ·¢Ê¼þµÄÖмäÈË¡£ÔÚÕâÖÖģʽÏ£¬Ò»¸ö¶ÔÏó²»ÓëÁíÍâµÄ¶ÔÏó²úÉúÖ±½ÓÁªÏµ£¬´Ó¶øʹµÃ¶ÔÏó¼ä¶¼»¥Ïà·ÖÀë¡£
¾ø²»Òª·µ»Øpromiseµ½Ò»¸ö¹«ÓõÄAPI¡£Õâ²»½ö¹Øϵµ½ÁËAPIÓû§¶ÔpromisesµÄʹÓã¬Ò²Ê¹µÃÖع¹¸ü¼ÓÀ§ÄÑ¡£²»¹ý£¬ÄÚ²¿ÓÃ;µÄpromisesºÍÍⲿ½Ó¿ÚµÄʼþµÄ½áºÏ£¬È´¿ÉÒÔÈÃÓ¦ÓøüµÍñîºÏÇÒ±ãÓÚ²âÊÔ¡£
ÔÚÏÈÇ°µÄÀý×ÓÀïÃ棬doSomethingCoolWithDirections»Øµ÷º¯ÊýÔÚÁ½¸ögeocodeº¯ÊýÍê³ÉºóÖ´ÐС£È»ºó£¬doSomethingCoolWithDirections²Å»á»ñµÃ´ÓgetRoute½ÓÊÕµ½µÄÏìÓ¦£¬ÔÙ½«Æä×÷ΪÏûÏ¢·¢ËͳöÈ¥¡£
- var doSomethingCoolWithDirections = function( route ) {
- postal.channel( "ui" ).publish( "directions.done", {
- route: route
- });
- };
ÕâÔÊÐíÁËÓ¦ÓõÄÆäËû²¿·Ö²»ÐèÒªÖ±½ÓÒýÓòúÉúÇëÇóµÄ¶ÔÏ󣬾ͿÉÒÔÏìÓ¦Òì²½»Øµ÷¡£¶øÔÚÈ¡µÃÃüÁîʱ£¬ºÜ¿ÉÄÜÒ³ÃæµÄºÃ¶àÇøÓò¶¼ÐèÒª¸üС£ÔÚÒ»¸öµäÐ͵ÄjQuery Ajax¹ý³ÌÖУ¬µ±½ÓÊÕµ½µÄÃüÁî±ä»¯Ê±£¬ÒªË³ÀûµÄ»Øµ÷¿ÉÄܾ͵Ã×öÏàÓ¦µÄµ÷ÕûÁË¡£Õâ¿ÉÄÜ»áʹµÃ´úÂëÄÑÒÔά»¤£¬µ«Í¨¹ýʹÓÃÏûÏ¢£¬´¦ÀíUI¶à¸öÇøÓòµÄ¸üоͻá¼òµ¥µÃ¶àÁË¡£
- var UI = function() {
- this.channel = postal.channel( "ui" );
- this.channel.subscribe( "directions.done", this.updateDirections ).withContext( this );
- };
- UI.prototype.updateDirections = function( data ) {
- // The route is available on data.route, now just update the UI
- };
- app.ui = new UI();
ÁíÍâһЩ»ùÓÚÖнéÕßģʽ´«ËÍÏûÏ¢µÄ¿âÓÐ amplify, PubSubJS, and radio.js¡£
½áÂÛ
JavaScript ʹµÃ±àдÒì²½´úÂëºÜÈÝÒ×. ʹÓà promises, ʼþ, »òÕßÃüÃûº¯ÊýÀ´±ÜÃâ“callback hell”. Ϊ»ñÈ¡¸ü¶àjavascriptÒì²½±à³ÌÐÅÏ¢,Çëµã»÷Async JavaScript: Build More Responsive Apps with Less . ¸ü¶àµÄʵÀýÍйÜÔÚgithubÉÏ£¬µØÖ·NetTutsAsyncJS£¬¸Ï¿ìClone°É !
ÔÎÄÁ´½Ó£ºhttp://www.oschina.net/translate/event-based-programming-what-async-has-over-sync
תÔØÇë×¢Ã÷£º ÎÄÕÂתÔØ×Ô£º°®Ë¼×ÊÔ´Íø http://www.aseoe.com/show-12-49-1.html