廖JS课程

1. 字符串


  • ASCII字符可以以\#XX形式的十六进制表示,例如:
'\x41' // 等同于A
  • 还可以用\u####表示一个Unicode字符:
'\u4e2d\u6587' // 等同于'中文'
  • 由于多行字符串用\n写起来比较费事,所以最新的ES6标准新增了一种多行字符串的表示方法,* ... *表示:
alert(`多行
字符串
测试`);

2. 数组


  • 多维数组
    举例,构建二维数组,规模为mxn,值全部初始化为initial
    构建一个二维数组

3. 对象


  • JS中有一点很奇特,就是JavaScript规定,访问一个对象中不存在的属性不报错,而是返回undefined

4. Map和Set


JavaScript的默认对象表示方式{}可以视为其他语言中的MapDictionary的数据结构,即一组键值对。
 但是JavaScript的对象有个小问题,就是键必须是字符串。但实际上Number或者其他数据类型作为键也是非常合理的
 为了解决这个问题,最新的ES6规范引入了新的数据类型Map

4.1 Map

Map是一组键值对的结构,具有极快的查找速度。
 举个例子,假设要根据同学的名字查找对应的成绩,如果用Array实现,需要两个Array

var names = ['Michael', 'Bob', 'Tracy'];
var scores = [95, 75, 85];

给定一个名字,要查找对应的成绩,就先要在names中找到对应的位置,再从scores取出对应的成绩,Array越长,耗时越长。
 如果用Map实现,只需要一个“名字”-“成绩”的对照表,直接根据名字查找成绩,无论这个表有多大,查找速度都不会变慢。用JavaScript写一个Map如下:

var m = new Map([['Michael', 95], ['Bob', 75], 
        ['Tracy', 85]]);
m.get('Michael'); // 95

通过上面的例子,可以看出Map其实看成一个二维数组,Map中的每一个元素都是一个一维数组,有一个key 和 与之对应的一个value

  • Map的具体操作
     初始化Map需要一个二维数组,或者直接初始化一个空Map
    Map的具体操作

     由于一个key只能对应一个value,所以,多次对一个key放入value,后面的值会把前面的值冲掉:
    Map的值覆盖

4.2 Set

SetMap类似,也是一组key的集合,但不存储value。由于key不能重复,所以,在Set中,没有重复的key
 要创建一个Set,需要提供一个Array作为输入,或者直接创建一个空Set

var s1 = new Set(); // 空Set
var s2 = new Set([1, 2, 3]); // 含1, 2, 3

重复元素在Set中自动被过滤

var s = new Set([1, 2, 3, 3, '3']);
s; // Set {1, 2, 3, "3"}

通过add(key)方法可以添加元素到Set中,可以重复添加,但不会有效果

>>> s.add(4)
>>> s
{1, 2, 3, 4}
>>> s.add(4)
>>> s
{1, 2, 3, 4}

通过delete(key)方法可以删除元素:

var s = new Set([1, 2, 3]);
s; // Set {1, 2, 3}
s.delete(3);
s; // Set {1, 2}

5. iterable


遍历Array可以采用下标循环,遍历MapSet就无法使用下标
 为了统一集合类型,ES6标准引入了新的iterable类型,ArrayMapSet都属于iterable类型
 具有iterable类型的集合可以通过新的for ... of循环来遍历for ... of循环是ES6引入的新的语法。

  • iterable的使用
var a = ['A', 'B', 'C'];
var s = new Set(['A', 'B', 'C']);
var m = new Map([[1, 'x'], [2, 'y'], [3, 'z']]);
for (var x of a) { // 遍历Array 
  alert(x);
}
for (var x of s) { // 遍历Set 
  alert(x);
}
for (var x of m) { // 遍历Map 
  alert(x[0] + '=' + x[1]);
}
  • for...infor...of的区别
     for ... in循环由于历史遗留问题,它遍历的实际上是对象的属性名称。一个Array数组实际上也是一个对象,它的每个元素的索引被视为一个属性
     当我们手动给Array对象添加了额外的属性后,for ... in循环将带来意想不到的意外效果:
    `for ... in`的缺陷

     上面的例子中,for ... in循环将把name包括在内,但Arraylength属性却不包括在内
     for ... of循环则完全修复了这些问题,它只循环集合本身的元素
    `for...of`弥补了`for...in`的缺陷
  • iterable内置的forEach方法
     for...of方法相比,forEach方法更好。它接收一个函数,每次迭代就自动回调该函数。
     1. ArrayforEach
 var a = ['A', 'B', 'C'];
    a.forEach(function (element, index, array) { 
         // element: 指向当前元素的值 
         // index: 指向当前索引 
         // array: 指向Array对象本身
         alert(element);
 });

2. SetArray类似,但Set没有索引,因此回调函数最多两个参数

    var s = new Set(['A', 'B', 'C']);
    s.forEach(function (element, set) {
       console.log(element); // 'A','B','C'
    });

3. Map的回调函数参数依次为valuekeymap本身

    var m = new Map([[1, 'x'], [2, 'y'], [3, 'z']]);
    m.forEach(function (value, key, map) {
        console.log(value); // 'x','y','z'
    });

6. 函数


6.1 函数的定义与调用

  • arguments
     JavaScript还有一个免费赠送的关键字arguments,它只在函数内部起作用,和this关键字一样,并且永远指向当前函数的调用者传入的所有参数arguments类似Array,但它不是一个Array
     利用arguments,你可以获得调用者传入的所有参数。也就是说,即使函数不定义任何参数,还是可以拿到参数的值
     实际上arguments最常用于判断传入参数的个数。注意区别arguments.lengtharguments.callee.length前者是实际传入的参数的个数,后者是定义函数时,定义的形参的个数

  • rest参数
     由于JavaScript函数允许接收任意个参数,于是我们就不得不用arguments来获取所有参数:

    使用`arguments`获取额外传入的参数

     为了获取除了已定义参数ab之外的参数,我们不得不用arguments,并且循环要从索引2开始以便排除前两个参数,这种写法很别扭,只是为了获得额外的rest参数,有没有更好的方法?
     Duang!!!ES6标准引入了rest参数,上面的函数可以改写为:
    `rest`的使用

     注意:现在浏览器大都还不支持...rest的写法。

  • 小心你的return语句
     JavaScript引擎有一个在行末自动添加分号的机制,这可能让你栽到return语句的一个大坑:

function foo() {
    return
        { name: 'foo' };
}
console.log(foo()); // undefined
---> 相当于下面:
function foo() {
    return; // 自动添加了分号,相当于return undefined;
        { name: 'foo' }; // 这行语句已经没法执行到了
}

所以正确的多行写法是:

function foo() {
    return { // 这里不会自动加分号,因为{表示语句尚未结束
        name: 'foo'
    };
}

6.2 变量的作用域

  • 变量提升
     变量的声明会提升,但是赋值不会被提升
'use strict';
function foo() {
    var x = 'Hello, ' + y; // 'Hello, undefined'
    alert(x);
    var y = 'Bob';
}
foo();
  • 命名空间
     全局变量会绑定到window上,不同的JavaScript文件如果使用了相同的全局变量,或者定义了相同名字的顶层函数,都会造成命名冲突,并且很难被发现。
     减少冲突的一个方法是把自己的所有变量和函数全部绑定到一个全局变量中:
// 唯一的全局变量MYAPP:
var MYAPP = {};
// 其他变量:
MYAPP.name = 'myapp';
MYAPP.version = 1.0;
// 其他函数:
MYAPP.foo = function () {
    return 'foo';
};

把自己的代码全部放入唯一的名字空间MYAPP中,会大大减少全局变量冲突的可能。
 许多著名的JavaScript库都是这么干的:jQueryYUIunderscore等等。

  • 局部作用域
     由于JavaScript的变量作用域实际上是函数内部,是没有块级作用域这个概念的,我们在for循环等语句块中是无法定义具有局部作用域的变量的。
     为了解决块级作用域,ES6引入了新的关键字letlet替代var可以申明一个块级作用域的变量
使用`let`声明一个块级作用域
  • 常量
     由于varlet申明的是变量,如果要申明一个常量,在ES6之前是不行的,我们通常用全部大写的变量来表示“这是一个常量,不要修改它的值”。
     ES6标准引入了新的关键字const来定义常量,constlet都具有块级作用域
'use strict';
 const PI = 3.14;
 PI = 3; // 某些浏览器不报错,但是无效果!
 PI; // 3.14

6.3 generator

generator(生成器)是ES6标准引入的新的数据类型。一个generator看上去像一个函数,但可以返回多次
 先看一个generator的栗子:

`generator`的小栗子

 再举个栗子,fibnacci数列:
`generator`对象中的 `next( )`方法介绍

 直接调用一个generator和调用函数不一样,fib(5)仅仅是创建了一个generator对象,还没有去执行它
 调用generator对象有两个方法,一是不断地调用generator对象的next()方法,如上面的栗子所示。

  • generator对象的next( )方法
     next( )方法会执行generator的代码,然后,每次遇到yield x;就返回一个对象{value: x, done: true/false},然后“暂停”。返回的value就是yield的返回值,done表示这个generator是否已经执行结束了。如果donetrue,则value就是return的返回值
     当执行到donetrue时,这个generator对象就已经全部执行完毕,不要再继续调用next()了。

  • 使用for...of遍历generator对象
     第二个方法是直接用for ... of循环迭代generator对象,这种方式不需要我们自己判断done需要注意,使用for...of方法遍历不到return返回的值

  • generator的用处
     因为generator可以在执行过程中多次返回,所以它看上去就像一个可以记住执行状态的函数。利用这一点,写一个generator就可以实现需要用面向对象才能实现的功能。
      generator还有另一个巨大的好处,就是把异步回调代码变成“同步”代码。例如Ajax,举个栗子:

**为了保证异步事件的执行顺序,需要嵌套,十分丑陋**

像上面的例子中,回调越多,为了保证代码的执行顺序,代码嵌套的层级越多,代码越难看
  有了generator的美好时代,用AJAX时可以这么写:

使用`generator`展开异步事件

  看上去是同步的代码,实际执行是异步的

7. 标准对象


7.1 Date

  • 获取时区
     Date对象表示的时间总是按浏览器所在时区显示的,不过我们既可以显示本地时间,也可以显示调整后的UTC时间
    获取时区

     那么在JavaScript中如何进行时区转换呢?实际上,只要我们传递的是一个number类型的时间戳,我们就不用关心时区转换。任何浏览器都可以把一个时间戳正确转换为本地时间
  • 时间戳
     时间戳是个什么东西?时间戳是一个自增的整数,它表示从1970年1月1日零时整的GMT时区开始的那一刻,到现在的毫秒数。假设浏览器所在电脑的时间是准确的,那么世界上无论哪个时区的电脑,它们此刻产生的时间戳数字都是一样的,所以,时间戳可以精确地表示一个时刻,并且与时区无关
     所以,我们只需要传递时间戳,或者把时间戳从数据库里读出来,再让JavaScript自动转换为当地时间就可以了。
     要获取当前时间戳,可以用:
    获取当前时间戳

7.2 正则表达式

  • 贪婪匹配
     需要特别指出的是,正则匹配默认是贪婪匹配,也就是匹配尽可能多的字符。
    贪婪匹配

     由于\d+采用贪婪匹配,直接把后面的0全部匹配了,结果0*只能匹配空字符串了。
     必须让\d+采用非贪婪匹配(也就是尽可能少匹配),才能把后面的0匹配出来,加个?就可以让\d+采用非贪婪匹配。
    非贪婪匹配

     注意:上面两个例子中使用了^$,这样可以在全局上进行一次匹配。
  • 全局匹配
     全局匹配类似搜索,因此不能使用/^...$/,那样只会最多匹配一次

8. 面向对象编程


8.1 原型继承

在传统的基于Class的语言如Java、C++中,继承的本质是扩展一个已有的Class,并生成新的Subclass
 由于这类语言严格区分类和实例,继承实际上是类型的扩展。但是JavaScript由于采用原型继承,我们无法直接扩展一个Class,因为根本不存在Class这种类型
 比较新颖的继承方法的实现:

原型继承

9. 浏览器


由于JavaScript的出现就是为了能在浏览器中运行,所以,浏览器自然JavaScript开发者必须要关注的。
 目前主流的浏览器分这么几种:

  • IE 6~11:国内用得最多的IE浏览器,历来对W3C标准支持差。从IE10开始支持ES6标准
  • ChromeGoogle出品的基于Webkit内核浏览器,内置了非常强悍的JavaScript引擎——V8。由于Chrome一经安装就时刻保持自升级,所以不用管它的版本,最新版早就支持ES6了;
  • SarafiApple的Mac系统自带的基于Webkit内核的浏览器,从OS X10.7 Lion自带的6.1版本开始支持ES6,目前最新的OS X 10.10 Yosemite自带的Sarafi版本是8.x,早已支持ES6;
  • FirefoxMozilla自己研制的Gecko内核和JavaScript引擎OdinMonkey。早起的Firefox按版本发布,后来终于聪明地学习Chrome的做法进行自升级,时刻保持最新
  • 移动设备上目前iOSAndroid两大阵营分别主要使用AppleSafariGoogleChrome,由于两者都是Webkit核心,结果HTML5首先在手机上全面普及(桌面绝对是Microsoft拖了后腿),对JavaScript的标准支持也很好,最新版本均支持ES6
     其他浏览器如Opera等由于市场份额太小就被自动忽略了。
     另外还要注意识别各种国产浏览器,如某某安全浏览器,某某旋风浏览器,它们只是做了一个壳,其核心调用的是IE,也有号称同时支持IE和Webkit的“双核”浏览器
     不同的浏览器对JavaScript支持的差异主要是,有些API的接口不一样,比如AJAX,File接口。对于ES6标准,不同的浏览器对各个特性支持也不一样
     在编写JavaScript的时候,就要充分考虑到浏览器的差异,尽量让同一份JavaScript代码能运行在不同的浏览器上。
     JavaScript可以获取浏览器提供的很多对象,并进行操作:
  • window
     window对象不但充当全局作用域,而且表示浏览器窗口。
     window对象有innerWidthinnerHeight属性,可以获取浏览器窗口的内部宽度和高度。内部宽高是指除去菜单栏、工具栏、边框等占位元素后,用于显示网页的净宽高
     注意:IE <= 8 不兼容这两个属性的
  • navigator
     navigator对象表示浏览器的信息,最常用的属性包括:

navigator.appName:浏览器名称;
navigator.appVersion:浏览器版本;
navigator.language:浏览器设置的语言;
navigator.platform:操作系统类型;
navigator.userAgent:浏览器设定的User-Agent字符串。

请注意navigator的信息可以很容易地被用户修改,所以JavaScript读取的值不一定是正确的,尽量不要使用navigator.userAgent提供的用户代理字符串去判断客户端浏览器。
 正确的方法是充分利用JavaScript对不存在属性返回undefined的特性,直接用短路运算符||计算

var width = window.innerWidth || document.body.clientWidth;
  • screen
     screen对象表示屏幕的信息,常用的属性有:

screen.width:屏幕宽度,以像素为单位;
screen.height:屏幕高度,以像素为单位;
screen.colorDepth:返回颜色位数,如8、16、24;

  • location
     location对象表示当前页面的URL信息。例如,一个完整的URL

    一条完整的URL

     可以用location.href获取。要获得URL各个部分的值,可以这么写:
    使用`location` 对象的不同属性获取 `URL` 中各部分的值

     要加载一个新页面,可以调用location.assign(),使用location.href也是可以的。如果要重新加载当前页面,调用location.reload()方法非常方便。

  • document
     document对象表示当前页面。由于HTML在浏览器中以DOM形式表示为树形结构,document对象就是整个DOM数的根节点。
     document对象还有一个cookie属性,可以获取当前页面的Cookie
     聊聊Cookie
     Cookie是由服务器发送的key-value标示符。因为HTTP协议是无状态的,但是服务器要区分到底是哪个用户发过来的请求,就可以用Cookie来区分。当一个用户成功登录后,服务器发送一个Cookie给浏览器,例如user=ABC123XYZ(加密的字符串)...,此后,浏览器访问该网站时,会在请求头附上这个Cookie,服务器根据Cookie即可区分出用户。
     为了防止XSS盗取Cookie中重要的信息,服务器在设置Cookie时可以使用httpOnly,设定了httpOnlyCookie将不能被JavaScript读取。这一类Cookie称为HTTP专有cookieHTTP专有cookie可以从浏览器或者服务器设置,但是只能从服务器端读取,因此JavaScript无法获取HTTP专有cookie的值。
     为了确保安全,服务器端在设置Cookie时,应该始终坚持使用httpOnly。

  • history
     history对象保存了浏览器的历史记录,JavaScript可以调用history对象的back()forward (),相当于用户点击了浏览器的“后退”或“前进”按钮。
     这个对象属于历史遗留对象,对于现代Web页面来说,由于大量使用AJAX页面交互,简单粗暴地调用history.back()可能会让用户感到非常愤怒。
     新手开始设计Web页面时喜欢在登录页登录成功时调用history.back(),试图回到登录前的页面。这是一种错误的方法。
     任何情况,你都不应该使用history这个对象了。

10. DOM操作


  • element.insertBefore(newNode, referenceNode);
  • element.insertAdjacentHTML(positionString,insertHTML);

positionString:
beforeBegin afterBegin beforeEnd afterEnd

11. 表单操作

  • form元素的submit事件的事件监听函数中,return true告诉来告诉浏览器继续提交return false表示浏览器将不会提交表单,这种情况通常对应用户输入有误,提示用户错误信息后终止提交form。
  • 没有name属性的<input>的数据不会被提交

12. 操作文件


在HTML表单中,可以上传文件的唯一控件就是<input type="file">
 尤其需要注意:

当一个表单包含<input type="file">时,表单的enctype必须指定为multipart/form-datamethod必须指定为post,浏览器才能正确编码并以multipart/form-data格式发送表单的数据

出于安全考虑,浏览器只允许用户点击<input type="file">来选择本地文件,用JavaScript对<input type="file">value赋值是没有任何效果的。当用户选择了上传某个文件后,JavaScript也无法获得该文件的真实路径

JS无法获取上传文件的真实路径

 通常,上传的文件都由后台服务器处理,JavaScript可以在提交表单时对文件扩展名做检查,以便防止用户上传无效格式的文件

  • File API
     由于JavaScript对用户上传的文件操作非常有限,尤其是无法读取文件内容,使得很多需要操作文件的网页不得不用Flash这样的第三方插件来实现
     随着HTML5的普及,新增的File API允许JavaScript读取文件内容,获得更多的文件信息
     HTML5File API提供了FileFileReader两个主要对象,可以获得文件信息并读取文件

13. Ajax


  • 兼容模式生成XHR对象


    兼容模式生成XHR对象
  • 原生Ajax写法步骤
     当创建了XMLHttpRequest对象后,要先设置onreadystatechange的回调函数。在回调函数中,通常我们只需通过readyState === 4判断请求是否完成,如果已完成,再根据status === 200(也可以写成(status >= 200 && status < 300) || status === 304)判断是否是一个成功的响应。
     XMLHttpRequest对象的open()方法有3个参数,第一个参数指定是GET还是POST,第二个参数指定URL地址,第三个参数指定是否使用异步,默认是true,所以不用写。
     注意,千万不要把第三个参数指定为false,否则浏览器将停止响应,直到AJAX请求完成。如果这个请求耗时10秒,那么10秒内你会发现浏览器处于“假死”状态。
     最后调用send()方法才真正发送请求。GET请求不需要参数,POST请求需要把body部分以字符串或者FormData对象传进去
  • 安全限制
     默认情况下,JavaScript在发送AJAX请求时,URL的域名必须和当前页面完全一致。这就是浏览器的同源策略造成的。
     完全一致的意思是域名要相同(www.example.comexample.com不同),协议要相同(http和https不同),端口号要相同(默认是:80端口,它和:8080就不同)。有的浏览器口子松一点,允许端口不同,大多数浏览器都会严格遵守这个限制。
     那是不是用JavaScript无法请求外域(就是其他网站)的URL了呢?方法还是有的,大概有这么几种
     1. 通过Flash插件发送HTTP请求,这种方式可以绕过浏览器的安全限制,但必须安装Flash,并且跟Flash交互。不过Flash用起来麻烦,而且现在用得也越来越少了。
     2. 通过在同源域名下架设一个代理服务器来转发,JavaScript负责把请求发送到代理服务器。
    代理服务器实现外域访问

     代理服务器再把结果返回,这样就遵守了浏览器的同源策略。这种方式麻烦之处在于需要服务器端额外做开发
     3.** 称为JSONP,它有个限制,只能用GET请求,并且要求返回JavaScript**。这种方式跨域实际上是利用了浏览器允许跨域引用JavaScript资源。
     以163的股票查询URL为例,对于URL:http://api.money.126.net/data/feed/0000001,1399001?callback=refreshPrice,你将得到如下返回:
refreshPrice({"0000001":{"code": "0000001", ... });

因此我们需要首先在页面中准备好回调函数:

function refreshPrice(data) {
    var p = document.getElementById('test-jsonp');
    p.innerHTML = '当前价格:' +
        data['0000001'].name +': ' + 
        data['0000001'].price + ';' +
        data['1399001'].name + ': ' +
        data['1399001'].price;
  }

最后用getPrice( )函数触发,就完成了跨域加载数据:

动态加入`<script>`元素

 4. CORS
 如果浏览器支持HTML5,那么就可以一劳永逸地使用新的跨域策略:CORS
 CORS全称Cross-Origin Resource Sharing,是HTML5规范定义的如何跨域访问资源
 了解CORS前,我们先搞明白概念:
 Origin表示本域,也就是浏览器当前页面的域。当JavaScript向外域(如sina.com)发起请求后,浏览器收到响应后,首先检查Access-Control-Allow-Origin是否包含本域,如果是,则此次跨域请求成功,如果不是,则请求失败,JavaScript将无法获取到响应的任何数据。
 可见,跨域能否成功,取决于对方服务器是否愿意给你设置一个正确Access-Control-Allow-Origin,决定权始终在对方手中
 上面这种跨域请求,称之为“简单请求”。简单请求包括GETHEADPOSTPOSTContent-Type类型仅限application/x-www-form-urlencodedmultipart/form-datatext/plain),并且不能出现任何自定义头(例如,X-Custom: 12345),通常能满足90%的需求。
 在引用外域资源时,除了JavaScript和CSS外,都要验证CORS。例如,当你引用了某个第三方CDN上的字体文件时:
使用@font-face引用 `第三方CDN`上的字体

 对于PUTDELETE以及其他类型如application/jsonPOST请求,在发送AJAX请求之前,浏览器会先发送一个OPTIONS请求(称为preflighted请求)到这个URL上,询问目标服务器是否接受:

OPTIONS /path/to/resource HTTP/1.1
Host: bar.com
Origin: http://bar.com
Access-Control-Request-Method: POST

服务器必须响应并明确指出允许的Method:

HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://foo.com
Access-Control-Allow-Methods: POST, GET, PUT, OPTIONS
Access-Control-Max-Age: 86400

浏览器确认服务器响应的Access-Control-Allow-Methods头确实包含将要发送的AJAX请求的Method,才会继续发送AJAX,否则,抛出一个错误。
 由于以POSTPUT方式传送JSON格式的数据在REST中很常见,所以要跨域正确处理POSTPUT请求,服务器端必须正确响应OPTIONS请求
 浏览器对CORS的实现情况:

  • IE8中引入了XDR类型
    XDR与XHR有一些不同之处:
    cookie不会随请求发送,也不会随响应返回;
    只能设置请求头部信息中的Content-Type字段;
    不能访问响应头部信息;
    只支持GET和POST方法;
     所有的XDR请求都是异步执行的,请求返回后,会触发load事件,但只能访问响应的原始文本(responseText),不能访问status,并且,只要响应有效就会触发load事件。如果失败(包括响应中缺少Access-Control-Allow-Origin头部)就会触发error事件
     为了支持POST请求,XDR对象提供了contentType属性,用来表示发送数据的格式。
  • 其他浏览器对CORS的支持
     其他支持HTML5的浏览器,都通过XHR对象实现对CORS的原生支持。要请求位于另一个域中的资源,使用标准的XHR对象并在open( )方法中传入绝对URL即可
     跨域的XHR对象可以访问status属性,而且还支持同步请求。不过,跨域XHR对象也会有一些限制
    不同使用setRequestHeader( )设置自定义头部;
    不能发送和接收cookie;
    调用getAllResponseHeader( )方法总会返回空字符串;
    注意以下内容,XDR和跨域XHR有如下共同属性/方法:
    abort( ):用于停止正在进行的请求
    onerror:用于替代onreadystatechange检测错误
    onload:用于替代onreadystatechange检测成功
    responseText:用于取得响应内容
    send( ):用于发送请求

跨浏览器的CORS

跨浏览器的`CORS`实现

14. promise


在JavaScript的世界中,所有代码都是单线程执行的。
 由于这个“缺陷”,导致JavaScript的所有网络操作,浏览器事件,都必须是异步执行。异步操作会在将来的某个时间点触发一个函数调用,AJAX就是典型的异步操作。

使用promise可以实现ajax的链式操作

 这种链式写法的好处在于,先统一执行AJAX逻辑,不关心如何处理结果,然后,根据结果是成功还是失败,在将来的某个时候调success函数或fail函数
 古人云:“君子一诺千金”,这种“承诺将来会执行”的对象在JavaScript中称为Promise对象
 Promise有各种开源实现,在ES6中被统一规范,由浏览器直接支持

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容