AJAX异步更新

什么是 AJAX ? AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML),意思就是用JavaScript执行异步网络请求。 AJAX 不是新的编程语言,而是一种使用现有标准的新方法。 AJAX 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新。 用JavaScript写一个完整的AJAX代码并不复杂,但是需要注意:AJAX请求是异步执行的,也就是说,要通过回调函数获得响应。 在现代浏览器上写AJAX主要依靠XMLHttpRequest对象

阅读全文

JS中的同步与异步

作用域

  • 作用域就是代码的执行环境,全局执行环境就是全局作用域,函数的执行环境就是私有作用域,它们都是栈内存。总的来说,作用域就是代码执行时开辟的栈内存。
总结 描述
私有作用域 函数执行都会形成一个私有作用域
全局作用域 页面一打开就会形成一个全局的作用域
私有变量 在私有作用域里边形成的变量 (通过 var 声明; 形参)
全局变量 在全局作用域形成的变量(var a = 12 或者函数内没有声明,直接赋值的变量)
  • 某个执行环境中所有的代码执行完毕后,该环境被销毁,保存在其中的所有变量和函数定义也随之销毁(全局执行环境直到应用程序退出时,如关闭浏览器或网页,才会被销毁)
  • 每个函数都有自己的执行环境。当执行流进入一个函数时,函数的环境就会被推入一个环境栈中。而在函数执行之后,栈将被环境弹出,把控制权返回给之前的执行环境。ECMAScript 程序中的执行流正是由这个方便的机制控制着。

作用域链

  • 当代码在一个环境中执行时,会创建变量对象的一个作用域链(作用域形成的链条)
  • 作用域链的前端,始终都是当前执行的代码所在环境的变量对象
  • 作用域链中的下一个对象来自于外部环境,而在下一个变量对象则来自下一个外部环境,一直到全局执行环境
  • 全局执行环境的变量对象始终都是作用域链上的最后一个对象
  • 内部环境可以通过作用域链访问所有外部环境,但外部环境不能访问内部环境的任何变量和函数。
  • 所以执行函数时,作用域链是从内到外来排序的。(有形参找形参,没有才找外部的全局变量)

形参与实参

参数 概念
形参(形式参数) 是在定义函数名和函数体的时候使用的参数,目的是用来接收调用该函数时传递的参数
实参(实际参数) 是在调用时传递给函数的参数,即传递给被调用函数的值
  • 形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只在函数内部有效。函数调用结束返回主调用函数后则不能再使用该形参变量。(随着函数被调用而新建,随着函数销毁而销毁)
  • 函数调用中发生的数据传送是单向的,即只能把实参的值传给形参,而不能把形参的值传给实参。因此,在函数调用的过程中,形参的值可以改变,而实参的值则不会变化。
  • 参考

执行栈

例子

注意:执行函数时,作用域链是从内到外来排序的。(有形参找形参,没有才找外部的全局变量

1
2
3
4
5
6
7
var count = 0;
function foo(count) {//count形参
count += 1;//私有变量count
console.log(count);//私有变量count
}
foo(count); // 1 count实参
foo(count); // 1
  • 函数的形参属于函数执行上下文,所以当指定这个形参后,它就随着函数被调用而新建,随着函数销毁而销毁
  • 指定了这个形参,调用函数时传递进来的实参count(0)会沿着作用域链找到私有变量 count(接下来的操作都在私有变量上进行),而不是全局变量count。

步骤

我们用执行栈来理解一下

  1. 函数每次被调用都会产生新的执行上下文(私有变量 count),实参count(全局变量count)的数据(0)被传入函数,私有变量 count变为0,并被压入执行栈,执行完毕后输出1,当前上下文接着被弹出执行栈,私有变量 count被销毁。
  2. 再次调用时又随着函数被调用而新建私有变量 count,重复第一步。
  3. 函数内的操作都在私有变量身上进行,随着私有变量的销毁上一次的操作就没了)所以第一次调用应该返回 1,第二次调用也应该返回 1,第 n 次调用都应该返回 1。
1
2
3
4
5
6
7
var count = 0;
function foo() {
count += 1;//全局变量count
console.log(count);//全局变量count
}
foo(count); // 1
foo(count); // 2
  • 函数的形参属于函数执行上下文,所以当指定这个形参后,它就随着函数被调用而新建,随着函数销毁而销毁。如果不指定这个形参,实参count(0)传进函数以后找不到形参就会沿着作用域链找到全局变量 count,它属于全局执行上下文,这个时候再去调用 foo() 函数就会读写这个全局变量(也就是函数里的所有操作都是在全局变量上进行的)。
  • 全局变量不会随着函数的调用而新建,也不会随着函数的销毁而销毁。
  • 每个 foo() 函数调用后,给 count(全局变量) 加一,然后被弹出执行栈,而全局执行上下文的生命周期将伴随着整个程序,所以第一次调用打印 1,第二次调用打印 2,第 n 次调用打印 n。

JS的同步与异步

为什么会有同步和异步

因为JavaScript是单线程,因此单一时间内只能处理单一任务,所有任务都需要排队,前一个任务执行完,才能继续执行下一个任务
但是,如果前一个任务的执行时间很长,比如文件的读取操作或ajax操作,后一个任务就不得不等着,拿ajax来说,当用户向后台获取大量的数据时,不得不等到所有数据都获取完毕才能进行下一步操作,用户只能在那里干等着,严重影响用户体验
因此,JavaScript在设计的时候,就已经考虑到这个问题,主线程可以完全不用等待文件的读取完毕或ajax的加载成功,可以先挂起处于等待中的加载任务,先运行排在后面的任务,等到文件的读取或ajax有了结果后,再回过头执行挂起的任务(这就是异步),因此,任务就可以分为同步任务和异步任务。

同步任务

同步任务是指在主线程上排队执行的任务,只有前一个任务执行完毕,才能继续执行下一个任务。
当我们打开网站时,网站的渲染过程,比如元素的渲染,其实就是一个同步任务。

异步任务

异步任务是指不进入主线程,而进入任务队列的任务,只有任务队列通知主线程,某个异步任务可以执行了,该任务才会进入主线程。
当我们打开网站时,像图片的加载,音乐的加载,其实就是一个异步任务


js的执行机制(事件循环)

  • 同步任务进入总线程,异步任务不会进入主线程,而是会先进入任务队列,任务队列其实是一个先进先出的数据结构,也是一个事件队列。
  • 比如说文件读取操作,因为这是一个异步任务,因此该任务会被添加到任务队列中,等到IO(输入输出)完成后,就会在任务队列中添加一个事件,表示异步任务准备好啦,可以进入执行栈啦~但是这时候呀,主线程不一定有空,当主线程处理完其它任务有空时,就会读取任务队列,读取里面有哪些事件,排在前面的事件会被优先进行处理,如果该任务指定了回调函数,那么主线程在处理该事件时,就会执行回调函数中的代码,也就是执行异步任务啦
  • 单线程从从任务队列中读取任务是不断循环的,每次栈被清空后,都会在任务队列中读取新的任务,如果没有任务,就会等,直到有新的任务,这就叫做任务循环,因为每个任务都是由一个事件触发的,因此也叫作事件循环

步骤总结

  1. 所有同步任务都在主线程上执行,行成一个执行栈
  2. 主线程之外,还存在一个任务队列,只要异步任务有了结果,就会在任务队列中放置一个事件
  3. 一旦执行栈中的所有同步任务执行完毕,系统就会读取任务队列,看看里面还有哪些事件,那些对应的异步任务,于是结束等待状态,(异步任务)进入执行栈,开始执行
  4. 主线程不断的重复上面的第三步

注意:同步任务由JS引擎执行,异步任务挂起时由浏览器的引擎执行,直到有了结果才放入任务队列等待被执行。

宏任务和微任务

  • 所有同步任务和异步任务又会分为宏任务和微任务,所以异步任务中也分先后。
  • 可参考笔记宏任务和微任务

js的异步编程

回调函数

这是异步编程最基本的方法。

  • 例:假定有两个函数f1和f2,后者等待前者的执行结果,如果f1是一个很耗时的任务,可以考虑改写f1,把f2写成f1的回调函数。【此时f2是异步的,她耗费的时间并不影响同步任务的执行】
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    function f2() {
    console.log("f2");
    }
    console.log("start");
    function f1(callback) {
    console.log("f1");
    setTimeout(function () {
    callback();
    }, 1000);
    }
    f1(f2);
    console.log("end");
    // start f1 end f2

Promise

可参考笔记Promise1Promise2Promise3.

事件监听

任务的执行不取决于代码的顺序,而取决于某个事件是否发生。

  • 例:为f1绑定一个事件,当f1发生done事件,就执行f2。

发布/订阅

与”事件监听”类似。

  • 我们假定,存在一个”信号中心”,某个任务执行完成,就向信号中心”发布”(publish)一个信号,其他任务可以向信号中心”订阅”(subscribe)这个信号,从而知道什么时候自己可以开始执行。这就叫做”发布/订阅模式”(publish-subscribe pattern),又称”观察者模式”(observer pattern)。
  • 这种方法的性质与”事件监听”类似,但是明显优于后者。因为我们可以通过查看”消息中心”,了解存在多少信号、每个信号有多少订阅者,从而监控程序的运行。

前端使用异步的场景

  • 定时任务:setTimeout,setInverval(可参考笔记“setTimeout()与setInterval()”
  • 网络请求:ajax请求,动态<img>加载
  • 事件绑定:事件函数绑定以后并不会等触发事件函数才继续执行程序,程序照常执行,等需要触发的时候才会执行事件绑定函数。

百度前端技术学院 第三天学习总结(CSS文本、选择器)(1)

补充:HTML知识title 属性 规定关于元素的额外信息。 这些信息通常会在鼠标移到元素上时显示一段工具提示文本(tooltip text)。 提示:title 属性常与 form 以及 a 元素一同使用,以提供关于输入格式和链接目标的信息。同时它也是 abbr 和 acronym 元素的必需属性。

阅读全文