js 先执行同步任务,异步任务会先放入event table内再经过event queue排队执行
AJAX原理
先创建一个AJAX对象通过XMLHttpRequest
通过open方法打开一个连接
通过send发送请求
通过onreadyStatechange事件监听服务器的返回数据
Promise
Promise内的代码在new的时候也是同步代码,例如下面的情况会先输入1再输入2
let p = new Promise((resolve,reject) =>{ console.log(1) resole() }) console.log(2) p.then() // 3
Promise的状态不可以逆,例如resole之后就不能再执行reject了
Promise的常用静态方法,无需new操作
Promise.resolve // 应用场景,简单返回一个结果为字符串的Promise对象
Promise.reject // 应用场景,简单返回一个结果为字符串的Promise对象
Promise.all // 应用场景,遍历图片数组,全部上传成功后提示用户完成
promise.race // 应用场景图片加载超时
Generator
Generator函数设计的意思重点是把异步操作放到yeild表达式中,等调用next之后再执行,也是解决回调地狱的一种方案,其实后面es7的async await更好
生成器函数最基本的用法
// 定义个生成器函数,一般会在function后面加上一个星号来表示 let foo = function* () { for (let i = 0; i < 3; i++) { yield i } } // 将生成器函数肤质给一个变量,注意此时生成器函数内部的for循环并不会执行,可以在yield i 上面打印个log测试一下 let f = foo() // 调用f下的next()方法,最后一次因为循环结束,所以没有值被返回 console.log(f.next()) // {value:0, done:false} console.log(f.next()) // {value:1, done:false} console.log(f.next()) // {value:2, done:false} console.log(f.next()) // {value:undefined, done:true}
Generator不能被当做构造函数的方式被使用,换句话说就是不能被new,会报错foo is not a constructor
yield 关键字只能在Generator函数内部使用。例如将上面的for循环改成forEach则会因为作用域的问题报错
一个最典型的应用场景,写一个函数用来生成7得倍数
function* gen(i = 0) { while (true) { if (i % 7 === 0) { yield i } i++ } } let g = gen() console.log(g.next()) // 0 console.log(g.next()) // 7 console.log(g.next()) // 14
解决ajax的回调地狱场景,例如有三个接口有依赖关系,常规的写法是嵌套的方式把下一个接口写到回调函数中,使用生成器可以用下面这种写法
function request(url,data = 0) { // 使用setTimeout来比喻ajax setTimeout(function () { reportData.next(data + 1) // 每次都根据上一次的返回结果去请求下一个接口 }, 1000) } function* gen() { let res1 = yield request('api/1') console.log(res1) // 1 let res2 = yield request('api/2',res1) console.log(res2) // 2 let res3 = yield request('api/3',res2) console.log(res3) // 3 } let reportData = gen() reportData.next() // 开始第一次
Iterator
迭代器是一种接口机制,为不同的数据结构提供统一的访问机制
主要服务与for...of,让步支持遍历的数据结构可遍历
先手写一个迭代器,感觉和Generator非常像
// 手写一个迭代器 function myIterator(arr) { let index = 0 return { next() { // 这里或者用循环的方式写也可以 return index < arr.length ? { value: arr[index++], done: false } : { value: undefined, done: true } } } } let it = myIterator ([1,2,3]) console.log(it.next()) console.log(it.next()) console.log(it.next()) console.log(it.next())
一个可迭代的对象,它的属性中必需要有一个Symbol(Symbol.iterator)属性,可以打印一个数组对象然后看看它的Prototype下面属性值Symbol(Symbol.iterator)
例如:
let arr = [1,2,3] let it = arr[Symbol.iterator]() // 因为数组Prototype下有Symbol.iterator这个迭代器 console.log(it.next()) console.log(it.next()) console.log(it.next())
原生具备Iterator接口的数据结构
Array
Map
Set
String
TypedArray
arguments对象
NodeList对象
可迭代协议: Symbol.iterator
迭代器协议:return { next(){ return{value, done} }
例子:为一个不可迭代的对象添加迭代协议
// 一个不能迭代的对象 let course = { allCourse: { frontEnd: ['es', 'mp', 'vue'], backEnd: ['java', 'python'], webapp: ['android', 'ios'] } } // 自己为这个对象实现一个迭代器协议 course[Symbol.iterator] = function* () { let allCourse = this.allCourse let keys = Reflect.ownKeys(allCourse) let values = [] while (true) { if (!values.length) { if (keys.length) { values = allCourse[keys[0]] keys.shift() yield values.shift() } else { return false } } else { yield values.shift() } } } // 可以用for...of遍历了 for(let c of course){ console.log(c) }
模块化
CommonJs :基于Node.js
AMD:require.js 依赖前置
CMD::sea.js 就近原则
UMD:集结了 CommonJs、CMD、AMD 的规范于一身
ES6:2015年原生js提供的模块化规范
关键字
export
import
as
export default