js作用域、异步——学习笔记

  所有的 for if switch while do 等等,都属于块级作用域,里面声明的对象,外面也能访问。但function 函数里的作用域,在函数外是访问不到的。

  但函数作用域里面可以访问外面。

  内层永远可以访问外层的。

  这就叫闭包,同时是一个立刻执行的匿名函数。

  你给他加个名字也可以,不过这里可以省略名字,闭包中的函数可以匿名。

  把一个函数的声明,用 () 括起来表示调用这个函数,然后再跟一个(),表示执行这个函数。等于把一个函数的声明和调用一句代码完成了。

  所以这里,这个函数执行的时候,b 还是会报错, done不会出来。

  我们改写一下,用一个setTimeout 把刚才的函数传进去,不需要设延迟,也就是说立刻执行它。

  虽然报错,但是done打印出来了,也就是说,带有错误的代码执行了,后文的代码也执行了。

  这就叫异步,setTimeout中的代码,等于另开了一个线程去执行它的上下文,而后面的代码不会等待setTimeout里的代码执行完,而是立刻继续往后执行。

  本来是同步顺序执行,遇到setTimeout后就分叉了,两条路同时开始执行,这就叫异步。 

  改成上图这样,timer done 同样是打印不出来的。因为在另一条路setTimeout的函数中,代码依然按照同步顺序来执行。遇到错误就退出了。但仅仅只是setTimeout里的程序退出了,原本的程序继续运行。

  试想一下,我如果想在timeout的异步程序执行结束之后,做一点什么操作,怎么判断它执行完了呢?

  比如,现在有一个程序可以帮我运算出sum,但是它可能需要点时间才能算好,我怎么知道在什么时候才能得到sum的值?从而进行下一步操作?(因为异步执行,如果不等setTimeout执行完就打印sum,它还并没有赋值)

  我们让这个程序运算的久一点,模仿一个复杂的程序。

  此时,我们可以用一个回调函数。

  我们加一个参数,这个参数是一个函数,这个函数在异步程序执行到最后会运行。我们在调用这个程序时,传入一个函数,这个就叫回调函数。它是在异步程序执行完后,能反馈给你结果的函数。

  这个函数是在下面调用程序时声明的,然后它会在异步程序执行完时调用运行。所以当这个函数运行的时候,前文的sum是已经算完了。

  我们再改造一下,程序功能要完成,不需要在外面额外声明一个sum。我希望只要传给程序两个值,它就能反给我结果。于是可以把结果,作为参数传给回调函数,这样我们调用时就可以直接拿来用。

  记住 js 中有几个原生的异步方法:setTimeout、setInterval、ajax,以后还有更多,目前只用记住这三个。

  jq的$.get post ajax 等等都是异步程序,异步程序必须要在回调中执行等待结果的代码。当用一个异步的程序时其实就是下图这个意思。

  要相信 异步程序 这个小伙伴,它处理完后一定会帮你做你交代的事情的。

  这比起setInterval来判断异步程序执行完毕的优势在于不用开另一个异步程序,并且很及时,不用考虑轮询的频率,和时间误差。不用考虑是否要关闭轮询的异步程序。

  我们不用回调,还有一种写法,就是使用事件。事件的机制比喻一下就是:在异步程序执行完以后,大声广播,我执行完了。再给某些对象或者dom绑定一个事件监听,它听到“执行完了”以后就执行自己的程序。

  回调和事件,各有好处,不分高低。不同的情形下用不同的机制。回调简单易用,但增加了耦合性,事件的好处是,监听者和广播者可以互不干涩,只管做自己的事。你做完了自己的事只用喊一声,“我做完了”,就不用管别人,其他人听到你做完了以后,有需要触发自己的程序的,都是他们自己的事了,他们自己会知道怎么做。

  回调:主程序需要告诉异步程序,你完成以后需要做什么。

  事件:监听者只用告诉触发者,你完成以后只用大声喊,不用做什么,我会听到。

  事件的机制使每个程序只用关心自己的事,在听到不同的广播时做不同的事就行。事件主要要做两个操作,给谁绑事件,及谁来监听事件,再就是谁来触发事件,即谁来广播事件。

  简单来说,回调和事件的区别,就是线程结束之后,交代的事情由哪个线程做,是不同的。回调是把事情交代给别的线程做,而事件是等别的线程结束之后自己做。

 

最后,感谢大神CX的讲解。

posted @ 2015-12-27 12:27  lovelyun  阅读(777)  评论(0编辑  收藏  举报