前端综合学习笔记---异步、ES6/7、Module、Promise同步 vs 异步
个人bolg地址
同步 vs 异步
先看下面的 demo,根据程序阅读起来表达的意思,应该是先打印100,1秒钟之后打印200,最后打印300。但是实际运行根本不是那么回事
console.log(100)
setTimeout(function () {
console.log(200)
}, 1000)
console.log(300)
再对比以下程序。先打印100,再弹出200(等待用户确认),最后打印300。这个运行效果就符合预期要求。
console.log(100)
alert(200) // 1秒钟之后点击确认
console.log(300)
这俩到底有何区别?—— 第一个示例中间的步骤根本没有阻塞接下来程序的运行,而第二个示例却阻塞了后面程序的运行。前面这种表现就叫做 异步(后面这个叫做 同步 ),即不会阻塞后面程序的运行。
异步和单线程
JS 需要异步的根本原因是 JS 是单线程运行的,即在同一时间只能做一件事,不能“一心二用”。
一个 Ajax 请求由于网络比较慢,请求需要 5 秒钟。如果是同步,这 5 秒钟页面就卡死在这里啥也干不了了。异步的话,就好很多了,5 秒等待就等待了,其他事情不耽误做,至于那 5 秒钟等待是网速太慢,不是因为 JS 的原因。
讲到单线程,我们再来看个真题:
第一问:下面代码的执行过程和结果
var a = true;
setTimeout(function(){
a = false;
}, 100)
while(a){
console.log('while执行了')
}
这是一个很有迷惑性的题目,不少候选人认为100ms之后,由于a变成了false,所以while就中止了,实际不是这样,因为JS是单线程的,所以进入while循环之后,没有「时间」(线程)去跑定时器了,所以这个代码跑起来是个死循环!
前端异步的场景
- 定时
setTimeoutsetInverval - 网络请求,如
Ajax<img>加载
Ajax 代码示例
console.log('start')
$.get('./data1.json', function (data1) {
console.log(data1)
})
console.log('end')
img 代码示例(常用于打点统计)
console.log('start')
var img = document.createElement('img')
// 或者 img = new Image()
img.onload = function () {
console.log('loaded')
img.onload = null
}
img.src = '/xxx.png'
console.log('end')
ES6/7 新标准的考查
第二问:ES6 箭头函数中的this和普通函数中的有什么不同
箭头函数
箭头函数是 ES6 中新的函数定义形式,function name(arg1, arg2) {...}可以使用(arg1, arg2) => {...}来定义。示例如下:
// JS 普通函数
var arr = [1, 2, 3]
arr.map(function (item) {
console.log(index)
return item + 1
}) // ES6 箭头函数
const arr = [1, 2, 3]
arr.map((item, index) => {
console.log(index)
return item + 1
})
箭头函数存在的意义,第一写起来更加简洁,第二可以解决 ES6 之前函数执行中this是全局变量的问题,看如下代码
function fn() {
console.log('real', this) // {a: 100} ,该作用域下的 this 的真实的值
var arr = [1, 2, 3]
// 普通 JS
arr.map(function (item) {
console.log('js', this) // window 。普通函数,这里打印出来的是全局变量,令人费解
return item + 1
})
// 箭头函数
arr.map(item => {
console.log('es6', this) // {a: 100} 。箭头函数,这里打印的就是父作用域的 this
return item + 1
})
}
fn.call({a: 100})
第三问:ES6 模块化如何使用?
ES6 中模块化语法更加简洁,直接看示例。
如果只是输出一个唯一的对象,使用export default即可,代码如下
// 创建 util1.js 文件,内容如
export default {
a: 100
} // 创建 index.js 文件,内容如
import obj from './util1.js'
console.log(obj)
如果想要输出许多个对象,就不能用default了,且import时候要加{...},代码如下
// 创建 util2.js 文件,内容如
export function fn1() {
alert('fn1')
}
export function fn2() {
alert('fn2')
} // 创建 index.js 文件,内容如
import { fn1, fn2 } from './util2.js'
fn1()
fn2()
第四问:ES6 class 和普通构造函数的区别
class
class 其实一直是 JS 的关键字(保留字),但是一直没有正式使用,直到 ES6 。 ES6 的 class 就是取代之前构造函数初始化对象的形式,从语法上更加符合面向对象的写法。例如:
JS 构造函数的写法
function MathHandle(x, y) {
this.x = x;
this.y = y;
}
MathHandle.prototype.add = function () {
return this.x + this.y;
};
var m = new MathHandle(1, 2);
console.log(m.add())
用 ES6 class 的写法
class MathHandle {
constructor(x, y) {
this.x = x;
this.y = y;
}
add() {
return this.x + this.y;
}
}
const m = new MathHandle(1, 2);
console.log(m.add())
注意以下几点,全都是关于 class 语法的:
- class 是一种新的语法形式,是class Name {...}这种形式,和函数的写法完全不一样
- 两者对比,构造函数函数体的内容要放在 class 中的constructor函数中,constructor即构造器,初始化实例时默认执行
- class 中函数的写法是add() {...}这种形式,并没有function关键字
使用 class 来实现继承就更加简单了,至少比构造函数实现继承简单很多。看下面例子
JS 构造函数实现继承
// 动物
function Animal() {
this.eat = function () {
console.log('animal eat')
}
}
// 狗
function Dog() {
this.bark = function () {
console.log('dog bark')
}
}
Dog.prototype = new Animal()
// 哈士奇
var hashiqi = new Dog()
ES6 class 实现继承
class Animal {
constructor(name) {
this.name = name
}
eat() {
console.log(`${this.name} eat`)
}
}
class Dog extends Animal {
constructor(name) {
super(name) //调用父对象的构造函数
this.name = name
}
say() {
console.log(`${this.name} say`)
}
}
const dog = new Dog('哈士奇')
dog.say()
dog.eat()
注意以下两点:
- 使用
extends即可实现继承,更加符合经典面向对象语言的写法,如 Java - 子类的
constructor一定要执行super(),以调用父类的constructor
第五问:ES6 中新增的数据类型有哪些?
Set 和 Map
Set 和 Map 都是 ES6 中新增的数据结构,是对当前 JS 数组和对象这两种重要数据结构的扩展。由于是新增的数据结构,目前尚未被大规模使用,但是作为前端程序员,提前了解是必须做到的。先总结一下两者最关键的地方:
- Set 类似于数组,但数组可以允许元素重复,Set 不允许元素重复
- Map 类似于对象,但普通对象的 key 必须是字符串或者数字,而 Map 的 key 可以是任何数据类型
Set
// 例1
const set = new Set([1, 2, 3, 4, 4]);
console.log(set) // Set(4) {1, 2, 3, 4} // 例2
const set = new Set();
[2, 3, 5, 4, 5, 8, 8].forEach(item => set.add(item));
for (let item of set) {
console.log(item);
}
// 2 3 5 4 8
Set 实例的属性和方法有
- size:获取元素数量。
- add(value):添加元素,返回 Set 实例本身。
- delete(value):删除元素,返回一个布尔值,表示删除是否成功。
- has(value):返回一个布尔值,表示该值是否是 Set 实例的元素。
- clear():清除所有元素,没有返回值。
const s = new Set();
s.add(1).add(2).add(2); // 添加元素 s.size // s.has(1) // true
s.has(2) // true
s.has(3) // false s.delete(2);
s.has(2) // false s.clear();
console.log(s); // Set(0) {}
Set 实例的遍历,可使用如下方法
- keys():返回键名的遍历器。
- values():返回键值的遍历器。不过由于 Set 结构没有键名,只有键值(或者说键名和键值是同一个值),所以keys()和values()返回结果一致。
- entries():返回键值对的遍历器。
- forEach():使用回调函数遍历每个成员。
let set = new Set(['aaa', 'bbb', 'ccc']);
for (let item of set.keys()) {
console.log(item);
}
// aaa
// bbb
// ccc
for (let item of set.values()) {
console.log(item);
}
// aaa
// bbb
// ccc
for (let item of set.entries()) {
console.log(item);
}
// ["aaa", "aaa"]
// ["bbb", "bbb"]
// ["ccc", "ccc"]
set.forEach((value, key) => console.log(key + ' : ' + value))
// aaa : aaa
// bbb : bbb
// ccc : ccc
Map
Map 的用法和普通对象基本一致,先看一下它能用非字符串或者数字作为 key 的特性。
const map = new Map();
const obj = {p: 'Hello World'}; map.set(obj, 'OK')
map.get(obj) // "OK" map.has(obj) // true
map.delete(obj) // true
map.has(obj) // false
需要使用new Map()初始化一个实例,下面代码中set get has delete顾名即可思义(下文也会演示)。其中,map.set(obj, 'OK')就是用对象作为的 key (不光可以是对象,任何数据类型都可以),并且后面通过map.get(obj)正确获取了。 Map 实例的属性和方法如下:
size:获取成员的数量set:设置成员 key 和 valueget:获取成员属性值has:判断成员是否存在delete:删除成员clear:清空所有
const map = new Map();
map.set('aaa', 100);
map.set('bbb', 200); map.size // map.get('aaa') // map.has('aaa') // true map.delete('aaa')
map.has('aaa') // false map.clear()
Map 实例的遍历方法有:
keys():返回键名的遍历器。values():返回键值的遍历器。entries():返回所有成员的遍历器。forEach():遍历 Map 的所有成员。
const map = new Map();
map.set('aaa', 100);
map.set('bbb', 200); for (let key of map.keys()) {
console.log(key);
}
// "aaa"
// "bbb" for (let value of map.values()) {
console.log(value);
}
//
// for (let item of map.entries()) {
console.log(item[0], item[1]);
}
// aaa 100
// bbb 200 // 或者
for (let [key, value] of map.entries()) {
console.log(key, value);
}
// aaa 100
// bbb 200
Promise
Promise是 CommonJS 提出来的这一种规范,有多个版本,在 ES6 当中已经纳入规范,原生支持 Promise 对象,非 ES6 环境可以用类似 Bluebird、Q 这类库来支持。
Promise 可以将回调变成链式调用写法,流程更加清晰,代码更加优雅。
简单归纳下 Promise:三个状态、两个过程、一个方法,快速记忆方法:3-2-1
三个状态:pending、fulfilled、rejected
两个过程:
- pending→fulfilled(resolve)
- pending→rejected(reject)
一个方法:then
当然还有其他概念,如catch、 Promise.all/race,这里就不展开了。
关于 ES6/7 的考查内容还有很多,本小节就不逐一介绍了,如果想继续深入学习,可以在线看《ES6入门》。
前端综合学习笔记---异步、ES6/7、Module、Promise同步 vs 异步的更多相关文章
- .NET Core学习笔记(4)——谨慎混合同步和异步代码
原则上我们应该避免编写混合同步和异步的代码,这其中最大的问题就是很容易出现死锁.让我们来看下面的例子: private void ButtonDelayBlock_Click(object sende ...
- spring mvc 及NUI前端框架学习笔记
spring mvc 及NUI前端框架学习笔记 页面传值 一.同一页面 直接通过$J.getbyName("id").setValue(id); Set值即可 二.跳转页面(bus ...
- Webpack4 学习笔记三 ES6+语法降级为ES5
前言 此内容是个人学习笔记,以便日后翻阅.非教程,如有错误还请指出 Webpack 将es6.es7语法降级为es5 需要通过 babel JavaScript编译器. 安装: npm i babel ...
- ArcGIS API for JavaScript 4.2学习笔记[7] 鹰眼(缩略图的实现及异步处理、Promise、回调函数、监听的笔记)
文前说明:关于style就是页面的css暂时不做评论,因为官方给的例子的样式实在太简单了,照抄阅读即可. 这篇文章有着大量AJS 4.x版本添加的内容,如监听watch.Promise对象.回调函数. ...
- bootstrap 前端框架学习笔记
下面是一个基于 bootstrap 前端架构的最最基本的模板: (这里添加慕课网的学习笔记.) 1.认识一下 bootstrap 带来的优雅效果: 代码: <!DOCTYPE html> ...
- handsontable前端excel学习笔记
暂时没有好的中文资料,大概找了三遍随便看看,之后重点研究其github 1.Handsontable 学习笔记-Methods 2. Handsontable通用方法 3.handsontable的核 ...
- [深度学习] pytorch学习笔记(4)(Module类、实现Flatten类、Module类作用、数据增强)
一.继承nn.Module类并自定义层 我们要利用pytorch提供的很多便利的方法,则需要将很多自定义操作封装成nn.Module类. 首先,简单实现一个Mylinear类: from torch ...
- ES6学习笔记(十五)Generator函数的异步应用
1.传统方法 ES6 诞生以前,异步编程的方法,大概有下面四种. 回调函数 事件监听 发布/订阅 Promise 对象 Generator 函数将 JavaScript 异步编程带入了一个全新的阶段. ...
- 前端学习笔记之ES6快速入门
0x1 let和const let ES6新增了let命令,用于声明变量.其用法类似var,但是声明的变量只在let命令所在的代码块内有效. { let x = 10; var y = 20; } x ...
随机推荐
- mac 查看某个文件夹下所有隐藏文件(夹)的大小
du -d 1 -h 对应Linux的命令是: du -ah --max-depth=1
- Linux ipip隧道及实现
一.IP隧道技术 IP隧道技术:是路由器把一种网络层协议封装到另一个协议中以跨过网络传送到另一个路由器的处理过程.IP 隧道(IP tunneling)是将一个IP报文封装在另一个IP报文的技术,这可 ...
- docker 报错:x509: certificate has expired or is not yet valid
环境:centos 7 程序:docker 下载镜像报错: # docker pull centos Pulling repository centos FATA[0004] Get https:// ...
- easyui验证扩展
问题描述: 如上所示:当用户添加信息时,必须保证一个队伍一天只能有一条数据.所以在选择了报表日期的时候必须查询数据库里面当前队伍这一天的数据是否存在.如果不存在,即当前日期队伍没有数据,就可以进行数据 ...
- 使用Ajax发送http请求(get&post请求)
本文最初发表于博客园,并在GitHub上持续更新前端的系列文章.欢迎在GitHub上关注我,一起入门和进阶前端. 以下是正文. 同步和异步 同步和异步的概念 同步:必须等待前面的任务完成,才能继续后面 ...
- w !sudo tee %
w !sudo tee % 该命令可用于保存有权限的写文件
- Yii小部件
小部件 Yii提供了一套数据小部件widgets,这些小部件可以用于显示数据. DetailView小部件用于显示一条记录数据. ListView和GridView小部件能够用于显示一个拥有分页.排序 ...
- HDU - 3001 Travelling 状压dp + 三进制 [kuangbin带你飞]专题二
终于刷完搜索专题了. 题意:给定n个城市,每个城市参观不能超过两次,两个城市之间有道路通过需要花费X,求通过能所有城市的最小花费. 思路:每个城市有三个状态0,1,2,可用三进制存储所有城市的访问状态 ...
- nginx启动停止
nginx -s reload :修改配置后重新加载生效 nginx -s reopen :重新打开日志文件 nginx -t -c /path/to/nginx.conf 测试nginx配置文件是否 ...
- 排序算法java实现
1. 插入排序 原理:遍历到第N个元素的时候前面的N-1个元素已经是排序好的了,那么就查找前面的N-1个元素把这第N个元素放在合适的位置,如此下去直到遍历完序列的元素为止. 算法的复杂度也是简单 ...