1.promise
小知识点1:promise中的错误捕获
异步捕获不到,同步的也要一层层传递,换成async就可以在await外面套一个try来捕获了
小知识点2:Promise.resolve(x) 可以看作是 new Promise(resolve => resolve(x)) 的简写
async的返回值是一个promise。
await会将promise转为该有的内容,在await拿到之前,阻塞后面的代码。
await的好处是,对于多个异步请求进行阻塞实现某种意义上的同步,而且减少嵌套(尤其请求结果会作为中间值,是下一个请求的参数的情况),美化代码。
定义:是异步编程的一种解决方案。
从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。
状态的特点
Promise 异步操作有三种状态:pending(进行中)、fulfilled(已成功)和 rejected(已失败)。它将执行代码与处理结果分离。
then 方法
- then 方法接收两个函数作为参数,第一个参数是 Promise 执行成功时的回调,第二个参数是catch的参数,是 Promise 执行失败时的回调,两个函数只会有一个被调用。
then 方法的特点
在 JavaScript 事件队列的当前运行完成之前,回调函数永远不会被调用。
最简单的promise实例↓
function test(resolve, reject) {//resolve与reject是默认写法
var timeOut = Math.random() * 2;
//log('set timeout to: ' + timeOut + ' seconds.');
setTimeout(function () {
if (timeOut < 1) {
//log('call resolve()...');
resolve('200 OK');
}
else {
//log('call reject()...');
reject('timeout in ' + timeOut + ' seconds.');
}
}, timeOut * 1000);
}
new Promise(test).then(function (result) {
console.log('成功:' + result);
}).catch(function (reason) {
console.log('失败:' + reason);
});
自实现promise
then中先把回调添加到队列中,当resolve开始执行时也会去执行回调
// myPromise2.0
// 实现了普通类型和MyPromise类型的链式调用
// 但是Mypromise类型异步调用then还是很难实现
const PENDING = 'pending'
const RESOLVED = 'resolved'
const REJECTED = 'rejected'
function MyPromise(fn) {
const that = this
that.state = PENDING
that.value = null
that.resolvedCallbacks = []
that.rejectedCallbacks = []
this.resolveData = null; // resolve的抛出值
this.rejectData = null; // reject的抛出值
function resolve(value) {
if (that.state === PENDING) {
that.state = RESOLVED
that.value = value
that.resolvedCallbacks.map(cb => {
that.value = cb(that.value)
//console.log(that.value instanceof MyPromise)
if(that.value instanceof MyPromise) {
that.value = that.value.value;
}
return that.value
})
}
}
function reject(value) {
if (that.state === PENDING) {
that.state = REJECTED
that.value = value;
that.rejectedCallbacks.map(cb => cb(that.value));
}
}
try {
fn(resolve, reject)
} catch (e) {
reject(e)
}
}
MyPromise.prototype.then = function(onFulfilled, onRejected) {
const that = this
//对传入的两个参数做判断,如果不是函数将其转为函数
onFulfilled =
typeof onFulfilled === 'function' ?
onFulfilled :
v => v // onFulfilled = v => v
onRejected =
typeof onRejected === 'function' ?
onRejected :
r => {
throw r
}
if (that.state === PENDING) {
that.resolvedCallbacks.push(onFulfilled)
that.rejectedCallbacks.push(onRejected)
} else if (that.state === RESOLVED) {
onFulfilled(that.value)
} else {
onRejected(that.value)
}
return this;
}
promise.all并行限制自实现
function asyncPool(poolLimit, array, iteratorFn) {
let i = 0;
// 已经完成个数,只有finished == array.length才能resolve
let finished = 0;
const ret = [];
poolLimit = Math.min(poolLimit, array.length);
function fn(index , resolve) {
console.log(i)
// 前i个已经在队列中,也就是说下一个要添加入队列的index
i ++;
iteratorFn(array[index]).then(function(data){
finished ++;
ret.push(data);
if(i < array.length){
fn(i, resolve);
}
else if(finished == array.length){
resolve(ret);
}
})
}
return new Promise(function(resolve, reject) {
for(let j = 0;j < poolLimit;j ++){
fn(j, resolve);
}
})
}
const timeout = i => new Promise(resolve => setTimeout(() => resolve(i), i));
asyncPool(2, [1000, 5000, 3000, 2000], timeout).then(results => {
console.log(results)
});
2.数组里面有哪些遍历方法?es6
参考https://www.cnblogs.com/sunjuncoder/p/9895438.html
- for(){} 遍历
- forEach 遍历,forEach不能修改数组的值
- for-in 遍历
- for-of 遍历
- every()、some()、filter()、map()
3.es6新语法:let与const
var:一旦声明在当前函数中就可随意调用。
let命令:
代码块内有效;
es6之前是没有块级作用域概念的,只能用function双()来创建块级作用域,es6之后就有块级作用域了,所以产生了let变量
不能重复声明;
暂时性死区;
无变量提升;
const命令:
声明一个只读的常量,一旦声明,常量的值就不能改变;
- let是更完美的var,不是全局变量,具有块级函数作用域,大多数情况不会发生变量提升。
- const定义常量值,不能够重新赋值,如果值是一个对象,可以改变对象里边的属性值。
var 和 let的区别:
var 是在全局范围内有效、let代码块内有效
var 可以声明多次、 let只能声明一次;
let 不存在变量提升,var 会变量提升;
示例:
console.log(a); //ReferenceError: a is not defined
let a = "apple";
console.log(b); //undefined
var b = "banana";
变量 b 用 var 声明存在变量提升,所以当脚本开始运行的时候,b 已经存在了,但是还没有赋值,所以会输出 undefined。
变量 a 用 let 声明不存在变量提升,在声明变量 a 之前,a 不存在,所以会报错。
const 命令
暂时性死区:
var PI = "a";
if(true){
console.log(PI); // ReferenceError: PI is not defined
const PI = "3.1415926";
}
ES6 明确规定,代码块内如果存在 let 或者 const,代码块会对这些命令声明的变量从块的开始就形成一个封闭作用域。代码块内,在声明变量 PI 之前使用它会报错。
4.解构赋值
ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构
1.对象结构赋值
let { name } = obj; //创建了一个变量name,值=obj.name
2.函数参数结构赋值
function f1({ age,height }){
console.log(age);
console.log(height)
}
5.rest函数
用于获取函数的多余参数,这样就不需要使用arguments对象了。rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中。
function q(...args){
//验证args是不是数组?
console.log(args instanceof Array);//true
console.log(Object.prototype.toString.call(args));//"[object Array]"
console.log(Array.isArray(args)); //true es5中的新方法
console.log(args);
}
q(1,3,5);
q(2,3,4,5,6,7,8);
6.generator
形式:
function* fib(max) {//function后面跟个*
var
t,
a = 0,
b = 1,
n = 0;
while (n < max) {
yield a;//每次遇到yield,返回一个对象{value: x, done: true/false}
[a, b] = [b, a + b];
n ++;
}
//如果遇到return,就返回done:true
return;
//用处,让一个函数能返回多次,每次执行需要用fib.next()
}
7.apply、call、bind
call、apply和bind是Function对象自带的三个方法,都是为了改变函数体内部 this 的指向。call后面参数用逗号隔开,apply传数组,他们作为调用函数的参数。
bind返回的是一个新函数,你必须要调用才能执行,其他和call一样。(也就是说要多加一对括号)。
8.Async/Await和Promise的区别
async的实现:
是promise和generator的语法糖,每次await的内容相当于用yield来接受,如果接受到的value为promise,则等待promise完成才继续调用next函数进行下一次yield。
介绍:
- Async/Await是一种新的编写异步代码的方式。其他方式是回调或者Promise。
- Async/Await实质是构建在Promise和generator之上,它不能用于纯的回调或者Node.js的回调中。
- 和Promise一样,Async/Await是非阻塞的
- Async/Await很大的特点是,它可以让异步代码看起来就像同步代码那样,大大提高了异步代码的可读性。
主体函数之前使用了async关键字。在函数体内,使用了await关键字。当然await关键字只能出现在用async声明的函数体内。
async/await与promise对结果处理写法不太一样,一个使用then函数,以两个返回值作为参数,一个是用await写在promise前面,如果返回1就正常执行,如果返回0就不执行并且抛出异常。
async function add1(x){
let a=1;
return x+a;//该函数返回值不是x+a,而是一个promise,里面带着一个resolve,带着一个11
}
console.log(add1(10));
区别:
1.简约,不需要写then。
2.错误处理,promise方法如果promise本身出错就难以处理then方法中的error,除非再写一个catch。而用async/await就能捕获到。
3.条件判别,如果要用promise拉取数据并且根据这个数据判断要不要再拉取会产生很多嵌套,而用async/await的话简洁明了,嵌套少
4.中间值,如果需要先用一个或多个promise作中间值,最后在用这些promise作参数调用其他promise的话,代码可读性会很差,因为有很多嵌套,而async/await依然不用嵌套。
9.代理模式proxy
当用户不方便访问一个对象或者不满足需求时,用代理模式创建一个替代对象实现对源对象的访问,并且在代理对象上添加拦截行为。
优点:
- 拦截和监视外部对对象的访问
- 降低函数或类的复杂度
- 在复杂操作前对操作进行校验或对所需资源进行管理
proxy也可以解决跨域,搭建中间层,传输时中间层将域名转化为对方的域名,规避跨域问题。
10.generator自执行函数
function *gen(){
let a = yield 'a';
console.log(a);
let b = yield 'b';
console.log(b);
let c = yield 'c';
console.log(c);
}
function co(gen){
return new Promise((resolve,reject)=>{
let g = gen();
function next(lastValue){
let {value,done} = g.next(lastValue)
if(done){
resolve(lastValue);
}else{
next(value);
}
}
next();
})
}
co(gen).then((data)=>{
console.log(data);
},(reason)=>{
console.log(reason);
})
11.固定数量的promise并行
var p1 = function(){
return new Promise(function(resolve,reject){
setTimeout(function(){
console.log('i am p1');
resolve('11')
},1000)
})}
var p2 = function(){
return new Promise(function(resolve,reject){
setTimeout(function(){
console.log('i am p2');
resolve('22')
},1100)
})}
var p3 = function(){
return new Promise(function(resolve,reject){
setTimeout(function(){
console.log('i am p3');
resolve('33')
},1000)
})}
var p4 = function(){
return new Promise(function(resolve,reject){
setTimeout(function(){
console.log('i am p4');
resolve('44')
},1200)
})}
var p5 = function(){
return new Promise(function(resolve,reject){
setTimeout(function(){
console.log('i am p5');
resolve('55')
},1300)
})}
function fun(arr,n){
/* arr = arr.slice(0,n);
console.time()
Promise.all(arr.map((item)=>item())).then(function(...rest){
console.log(...rest);
console.timeEnd()
}) */
n = Math.min(arr.length,n);
var j = n;
for(var i = 0;i < n;i ++){
arr[i] = arr[i]().then(handler);
}
function handler(data){
console.log(data);
if(j < arr.length){
arr[j] = arr[j]().then(handler);
j ++;
}else{
return;
}
}
//var que = [];
//arr[0].then(()=>console.log('xx'))
}
fun([p1,p2,p3,p4,p5],2);
12.Object.defineProperty和proxy
Object.defineProperty
为什么他不能监听数组?
因为数组的length的configurable为false也不允许被改为true,描述符不能被改变导致数组length不能被监听到。
//参数1 目标对象
//参数2 key
//参数3 配置
//write 是否能直接赋值修改值
//enumerble 是否能枚举
//configurable 是否能删除和可配置,除value和writable特性外的其他特性是否可以被修改
let Person = {}
Object.defineProperty(Person, 'name', {
value: 'jack',
writable: true // 是否可以改变
})
proxy原理
proxy是对目标的一个拦截,拦截操作是在原型上,所以可以用Object.create进行继承,返回一个代理对象。
//常用handler操作
//1. get(target, propKey, receiver)
//2. set(target, propKey, value, receiver)
//3. has(target, propKey)
//4. construct(target, args):
//5. apply(target, object, args)
var target = {
name: 'poetries'
};
var logHandler = {
get: function(target, key) {
console.log(`${key} 被读取`);
return target[key];
},
set: function(target, key, value) {
console.log(`${key} 被设置为 ${value}`);
target[key] = value;
}
}
var targetWithLog = new Proxy(target, logHandler);
14.catch实现、all实现
Promise.prototype.myCatch = function (onRejected) {
return this.then(undefined, onRejected);
};
Promise.myAll = async function(...rest){
var n = rest.length;
var ans = new Array(n);
for(let i = 0;i < rest.length;i ++){
let p = await rest[i]
console.log(p)
n --;
ans[i] = p;
}
return new Promise((resolve)=>{
console.log(ans);
resolve(ans);
})
}