4.ES6
谈一谈 promise
promise和回调
异步任务指被引擎挂起的、不在主线程上排队的任务,只有在满足某种条件后,引擎认为可以执行了,异步任务才会进入主线程
回调函数(callback)是异步操作最基本的方法,代表着当异步操作完成就调用被传入的函数。
Promise对象有以下两个特点:
(1)对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。
(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)
promise.all
Promise.all可以将多个Promise实例包装成一个新的Promise实例。同时,成功和失败的返回值是不同的,成功的时候返回的是一个结果数组,而失败的时候则返回最先被reject失败状态的值。
promise.race
Promse.race就是赛跑的意思,意思就是说,Promise.race([p1, p2, p3])里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。
promise.resolve
返回fulfilled状态的promise对象
promise.reject
返回rejected状态的promise对象
深入解析promise源码及原理
- 使用方式
function buyPhone(url) {
return new Promise(function(resolve, reject) {
//异步请求
http.get(url, function(error, results) {
if (error) {
reject(error);
} else {
resolve(results.name)
}
})
})
}
buyPhone("129.168.1.1").then(function(name) {
//一些处理
}, function(error) {
console.log(error)
})
promise源码
function Promise(fn) {
var state = 'pending',
value = null,
callbacks = [];
this.then = function (onFulfilled, onRejected) {
return new Promise(function (resolve, reject) {
handle({
onFulfilled: onFulfilled || null,
onRejected: onRejected || null,
resolve: resolve,
reject: reject
});
});
};
function handle(callback) {
if (state === 'pending') {
callbacks.push(callback);
return;
}
var cb = state === 'fulfilled' ? callback.onFulfilled : callback.onRejected,
ret;
if (cb === null) {
cb = state === 'fulfilled' ? callback.resolve : callback.reject;
cb(value);
return;
}
try {
ret = cb(value);
callback.resolve(ret);
} catch (e) {
callback.reject(e);
}
}
function resolve(newValue) {
if (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) {
var then = newValue.then;
if (typeof then === 'function') {
then.call(newValue, resolve, reject);
return;
}
}
state = 'fulfilled';
value = newValue;
execute();
}
function reject(reason) {
state = 'rejected';
value = reason;
execute();
}
function execute() {
setTimeout(function () {
if (callbacks.length !== 0) {
callbacks.forEach(function (callback) {
handle(callback);
});
}
}, 0);
}
fn(resolve, reject);
}
Generator 函数
Generator函数一个状态机,封装了多个内部状态
还是一个遍历器对象生成函数
两个特征。一是,function关键字与函数名之间有一个星号,二是,函数体内部使用yield语句,定义不同的内部状态
调用Generator函数后,该函数并不知晓,返回是也不是函数运行结果,而是一个指向内部状态的指针对象,也就是遍历器对象
必须调用遍历器对象的next方法,似的指针移动到下一个状态。
function* helloWorldGenerator(){
yield 'hello';
yield 'world';
return 'ending';
}
var hw = helloWorldGenerator();
hw.next()
// {value:'hello', done:false}
hw.next()
// {value:'world', done:false}
hw.next()
// {value:'ending', done:false}
hw.next()
// {value:undefined, done:true}
async await原理
Await和Async其实就是promise的封装,使用编译技术自动将Await/Async转化为promise
async 函数就是 Generator 函数的语法糖。
var gen = function* (){
var f1,f2;
yield f1 = readFile('/etc/fstab');
yield f2 = readFile('/etc/shells');
console.log(f1.toString());
console.log(f2.toString());
};
vat interator = gen();
interator.next();
interator.next()
interator.next()
var asyncReadFile = async function (){
var f1 = await readFile('/etc/fstab');
var f2 = await readFile('/etc/shells');
console.log(f1.toString());
console.log(f2.toString());
};
asyncReadFile ()
所有的 ES6 特性
- let、const
let 定义的变量不会被变量提升,const 定义的常量不能被修改,let 和 const 都是块级作用域
2.import、export
import导入模块、export导出模块 - class、extends、super
在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”
Class之间可以通过extends关键字实现继承
super关键字,它指代父类的实例(即父类的this对象)。子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工。如果不调用super方法,子类就得不到this对象。
class personner {
constructor(name) {
this.name = name;
}
sayMyself() {
console.log("我是"+this.name)
}
static say() {
console.log("名字"+this.name)
}
}
personner.say()
//名字personner
class runner extends personner {
constructor(name,time) {
super(name);
this.time = time;
}
run() {
console.log(this.name+"跑步时间是"+this.time)
}
}
var runnerobj = new runner("jack","12hour")
runnerobj.run()
//jack跑步时间是12hour
runnerobj.sayMyself()
//我是jack
runner.say()
//名字runner
- arrow functions (箭头函数)
函数的快捷写法。不需要 function 关键字来创建函数,省略 return 关键字,继承当前上下文的 this 关键字 - template string (模板字符串)
字符串拼接。将表达式嵌入字符串中进行拼接,用和${}
来界定。 - destructuring (解构)
简化数组和对象中信息的提取。
ES6前,我们一个一个获取对象信息;
ES6后,解构能让我们从对象或者数组里取出数据存为变量 - default 函数默认参数
如果一个函数的最后一个形参是以 … 为前缀的,则在函数被调用时,该形参会成为一个数组,数组中的元素都是传递给该函数的多出来的实参的值 - Spread Operator (展开运算符)
组装数组,对象 - 对象
- 对象初始化简写(对象属性和放值的变量相同是,可以省略冒号和值)
- 对象字面量简写(省略冒号与 function 关键字)
- Object.assign()
ES6 对象提供了Object.assign()这个方法来实现浅复制。Object.assign()可以把任意多个源对象自身可枚举的属性拷贝给目标对象,然后返回目标对象。第一参数即为目标对象。在实际项目中,我们为了不改变源对象。一般会把目标对象传为{}
const obj = Object.assign({}, objA, objB)
// 给对象添加属性
this.seller = Object.assign({}, this.seller, response.data)
- Promise
用同步的方式去写异步代码 - Generators
生成器( generator)是能返回一个迭代器的函数。
生成器函数也是一种函数,最直观的表现就是比普通的function多了个星号*,在其函数体内可以使用yield关键字,有意思的是函数会在每个yield后暂停。
es6的继承和es5的继承有什么区别
es5的继承
function Super(){
this.flag = true;
}
Super.prototype.getFlag = function(){
return this.flag; //继承方法
}
function Sub(){
this.subFlag = flase
Super.call(this) //继承属性
}
Sub.prototype = new Super;
var obj = new Sub();
Sub.prototype.constructor = Sub;
Super.prototype.getSubFlag = function(){
return this.flag;
es6的继承
class ColorPoint extends Point {
constructor(x, y, color) {
super(x, y); // 等同于parent.constructor(x, y)
this.color = color;
}
toString() {
return this.color + ' ' + super.toString(); // 等同于parent.toString()
}
}
promise封装ajax
ajax的xhr对象有7个事件
onloadstart
开始send触发
onprogress
从服务器上下载数据每50ms触发一次
onload
得到响应
onerror
服务器异常
onloadend
请求结束,无论成功失败
onreadystatechange
xhr.readyState改变使触发
onabort
调用xhr.abort时触发
- 实现
function ajax(optionsOverride) {
// 将传入的参数与默认设置合并
var options = {};
for (var k in ajaxOptions) {
options[k] = optionsOverride[k] || ajaxOptions[k];
}
options.async = options.async === false ? false : true;
var xhr = options.xhr = options.xhr || new XMLHttpRequest();
return new Promise(function (resolve, reject) {
xhr.open(options.method, options.url, options.async);
xhr.timeout = options.timeout;
//设置请求头
for (var k in options.headers) {
xhr.setRuquestHeader(k, options.headers[k]);
}
// 注册xhr对象事件
xhr.onprogress = options.onprogress;
xhr.upload.onprogress = options.onuploadprogress;
xhr.responseType = options.dataType;
xhr.onabort = function () {
reject(new Error({
errorType: 'abort_error',
xhr: xhr
}));
}
xhr.ontimeout = function () {
reject({
errorType: 'timeout_error',
xhr: xhr
});
}
xhr.onerror = function () {
reject({
errorType: 'onerror',
xhr: xhr
})
}
xhr.onloadend = function () {
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304)
resolve(xhr);
else
reject({
errorType: 'status_error',
xhr: xhr
})
}
try {
xhr.send(options.data);
}
catch (e) {
reject({
errorType: 'send_error',
error: e
});
}
})
}
let const的优点
不存在变量提升:如果变量提升,内层变量覆盖外层相同变量,所以es6不允许这种情况,es5提示undefined、es6直接报错
.暂时性死区,绑定变量于相应块级作用域内、外部相同变量的声明无法修改作用域内变量
.不允许重复性声明
可以确保数据的回收,不会将子作用域的变量暴露于外层作用域中
ES6和node的commonjs模块化规范区别
-
ES6
export 和 import。export命令用于规定模块的对外接口,import命令用于输入其他模块提供的功能。 -
commonjs
module、exports、require、global。实际使用时,用module.exports定义当前模块对外输出的接口(不推荐直接用exports),用require加载模块。
//定义模块 math.js
var n = 0;
function add(a, b) {
return a + b;
}
module.exports = { //在这里写上需要向外暴露的函数、变量
add: add,
n: n
}
/** 引入模块 require **/
//引用自定义的模块时,参数包含路径,可省略.js
var math = require(‘./math‘);
math.add(2, 5);
//引用核心模块时,不需要带路径
var http = require(‘http‘);
http.createService(...).listen(3000);
网友评论