前端面试(一)

JavaScript中如何检测一个变量是一个String类型?请写出函数实现

function str(obj){
    rerurn typeof(obj) == 'string'
}
function str(obj){
    return obj.constructor === String
}
function type(data){
    return Object.prototype.toSting.call(data).slice(8,-1).toLowerCase();
}

请用js去除字符串空格?

正则:
var c = str.replace(/\s*/g,"")  //去除所有空格
var c = str.replace(/^\s*|\s*$/g,"")  //去除两头空格
var c = str.replace(/^\s*/,"")   //去除左空格
var c = str.replace(/(\s*$)/g,"")   //去除右空格
str.trim方法: str.trim()   //局限性:无法去除中间的空格,实例如下:
str.trimLeft(),str.trimRight()分别用于去除字符串左右空格。
jquery,$.trim(str)方法:  $.trim(str)  //局限性:无法去除中间的空格

DOM操作——怎样添加、移除、移动、复制、创建和查找节点

1)创建新节点:
createDocumentFragment() //创建一个DOM片段
createElement() //创建一个具体的元素
createTextNode() //创建一个文本节点
2)添加、移除、替换、插入
appendChild()  //末尾添加节点,也可移动节点ul.appendChild(ul.firstChild);
removeChild()
replaceChild()
insertBefore() //也可放在特定的位置上,该方法接受2个参数:insertBefore(插入的节点,参照节点);
3)查找:
getElementsByTagName() //通过标签名称
getElementsByName() //通过元素的Name属性的值
getElementById() //通过元素Id,唯一性
4)复制节点
cloneNode() 方法,用于复制节点, 接受一个布尔值参数,
true 表示深复制(复制节点及其所有子节点), false 表示浅复制(复制节点本身,不复制子节点)
var deepList = ul.cloneNode(true); //深复制

 addClass(),.removeClass(),.toggleClass()的区别

.addClass("className")方法是用来给指定元素增加类名,也就是说给指定的元素追加样式;可以同时添加多个类名,空格符隔开
$("selector").addClass("className1 className2");
.removeClass("className")方法是用来给指定的元素移除类名,也就是说给指定元素移除样式;可以同时移除多个类名,空格符隔开
$("selector").removeClass("className1 className2");
$("selector").removeClass();//这种方法将移除选择定元素的所有类名
.toggleClass("className")方法是用来给指定的元素添加或者移除类名(如果类名存在则移除,不存在则增加)
toggleClass()方法和addClass()方法一样,可以同时加多个或同时移除多个类名,不过他们之间需要用空格隔开,如:
$("selector").toggleClass("className1 className2");
无参数时,自动删除、恢复全部className,也可以传递一个布尔值,true为恢复class,false为删除class
三者之间的关系如下:
$("selector").toggleClass("className");
//等同于
$("selector").hasClass('className') ? $("selector").removeClass('className') : $("selector").addClass('className');
  

 document.ready和onload的区别

页面加载完成有两种事件
一是ready,表示文档结构已经加载完成(不包含图片等非文字媒体文件)
二是onload,指示页面包含图片等文件在内的所有元素都加载完成。
$(document).ready(function(){
//do something
})
jq ready()的方法就是Dom Ready,作用或者意义就是:在DOM加载完成后就可以可以对DOM进行操作。
一般情况下一个页面响应加载的顺序是:域名解析-加载html-加载js和css-加载图片等其他信息。
那么Dom Ready应该在“加载js和css”和“加载图片等其他信息”之间,就可以操作Dom了。
1.window.onload方法
⑴执行时机:
在网页中所有元素(包括元素的所有关联文件)完全加载到浏览器后才执行,即JavaScript 此时可以访问网页中的所有元素。
window.onload=function(){  $(window).load(function(){
}  }); 
⑵多次使用:
JavaScript的onload事件一次只能保存对一个函数的引用,他会自动用最后面的函数覆盖前面的函数。
2.$(document).ready()方法
⑴执行时机:在DOM完全就绪时就可以被调用。(这并不意味着这些元素关联的文件都已经下载完毕)
举个例子:$(document).ready()方法DOM就绪就可以操作了,不需要等待所有图片下载完毕。
⑵多次使用:可以多次
$(document).ready(function(){ one(); });
$(document).ready(function(){ two(); });

 setInterval与setTimeout的区别

setInterval()方法可按照指定的周期来调用函数或者计算表达式(以毫秒为单位)
语法: setInterval(函数表达式,毫秒数);
setInterval()会不停的调用函数,直到clearInterval()被调用或者窗口被关闭,由 setInterval()返回的ID值可用作clearInterval()方法的参数。
setTimeout()方法用于在指定毫秒数后再调用函数或者计算表达式(以毫秒为单位)
语法: setTimeout(函数表达式,毫秒数);
setTimeout()只执行函数一次,如果需要多次调用可以使用setInterval(),或者在函数体内再次调用setTimeout()
clearTimeout(): 要使用clearTimeout(),需要我们设定setTimeout()时, 给予这setTimeout()一个名称, 这名称就是timeoutID ,我们叫停时,就是用这 timeoutID 来叫停

 cookies,sessionStorage和localStorage的区别

相同点:都存储在客户端,且同源的。
cookie数据始终在同源的http请求中携带(即使不需要),即cookie在浏览器和服务器间来回传递。
sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存。
cookie数据还有路径(path)的概念,可以限制cookie只属于某个路径下。
存储大小限制也不同:
cookie数据不能超过4k,同时因为每次http请求都会携带cookie,所以cookie只适合保存很小的数据,如会话标识。
sessionStorage和localStorage 虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大。
数据有效期不同:
sessionStorage:仅在当前浏览器窗口关闭前有效,自然也就不可能持久保持;
localStorage:始终有效,窗口或浏览器关闭也一直保存,因此用作持久数据;
cookie只在设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭。
作用域不同:
sessionStorage不在不同的浏览器窗口中共享,即使是同一个页面;
localStorage 在所有同源窗口中都是共享的;
cookie也是在所有同源窗口中都是共享的。
Web Storage 支持事件通知机制,可以将数据更新的通知发送给监听者。Web Storage 的 api 接口使用更方便。
sessionStorage用于本地存储一个会话(session)中的数据,这些数据只有在同一个会话中的页面才能访问并且当会话结束后数据也随之销毁。 因此sessionStorage不是一种持久化的本地存储,仅仅是会话级别的存储。 而localStorage用于持久化的本地存储,除非主动删除数据,否则数据是永远不会过期的。

undefined 和 null 区别

判断:null和undefined 是否相等
console.log(null==undefined)//true
console.log(null===undefined)//false
null和undefined 两者相等,但是当两者做全等比较时,两者又不等。
null: Null类型,代表“空值”,代表一个空对象指针,使用typeof运算得到 “object”,所以你可以认为它是一个特殊的对象值。
undefined: Undefined类型,当一个声明了一个变量未初始化时,得到的就是undefined。
实际上,undefined值是派生自null值的,ECMAScript标准规定对二者进行相等性测试要返回true。
null是javascript的关键字,可以认为是对象类型,它是一个空对象指针,和其它语言一样都是代表“空值”,不过 undefined 却是javascript才有的。undefined是在ECMAScript第三版引入的,为了区分空指针对象和未初始化的变量,它是一个预定义的全局变量。没有返回值的函数返回为undefined,没有实参的形参也是undefined。
到底什么时候是null,什么时候是undefined呢?
null表示"没有对象",即该处不应该有值。典型用法是:
(1) 作为函数的参数,表示该函数的参数不是对象。
(2) 作为对象原型链的终点。
undefined表示"缺少值",就是此处应该有一个值,但是还没有定义。典型用法是:
(1)变量被声明了,但没有赋值时,就等于undefined。
(2) 调用函数时,应该提供的参数没有提供,该参数等于undefined。
(3)对象没有赋值的属性,该属性的值为undefined。
(4)函数没有返回值时,默认返回undefined。
个人理解: undefined是访问一个未初始化的变量时返回的值,而null是访问一个尚未存在的对象时所返回的值。因此,可以把undefined看作是空的变量,而null看作是空的对象。

 Ajax与JSON的区别:

Ajax技术的核心是XMLHttpRequest对象(简称XHR),可以通过使用XHR对象获取到服务器的数据,然后再通过DOM将数据插入到页面中呈现。虽然名字中包含XML,但Ajax通讯与数据格式无关,所以我们的数据格式可以是XML或JSON等格式。
XMLHttpRequest对象用于在后台与服务器交换数据,具体作用如下:
在不重新加载页面的情况下更新网页
在页面已加载后从服务器请求数据
在页面已加载后从服务器接收数据
在后台向服务器发送数据
XMLHttpRequest是一个JavaScript对象,它提供了一种简单的方法来检索URL中的数据。
要创建一个XMLHttpRequest实例,只需new一个:
var req = new XMLHttpRequest();
在创建XHR对象后,接着我们要调用一个初始化方法open()。
一是URL相对于执行代码的当前页面(使用绝对路径);二是调用open()方法并不会真正发送请求,而只是启动一个请求准备发送。
真正发送请求要使用send()方法,send()方法接受一个参数,即要作为请求主体发送的数据,如果不需要通过请求主体发送数据,我们必须传递一个null值。在调用send()之后,请求就会被分派到服务器
var req = new XMLHttpRequest();
req.open(
    "GET",
    "myxhrtest.aspx",
    false
);
req.send(null);
在发送请求之后,我们需要检查请求是否执行成功,首先可以通过status属性判断,一般来说,可以将HTTP状态代码为200作为成功标志。这时,响应主体内容会保存到responseText中。此外,状态代码为304表示请求的资源并没有被修改,可以直接使用浏览器缓存的数据,Ajax的同步请求代码如下:
if (req != null) {
    req.onreadystatechange = function() {
        if ((req.status >= 200 && req.status < 300) || req.status == 304) {
        }
        else {
            alert("Request was unsuccessful: " + req.status);
        }
    };
    req.open("GET", "www.myxhrtest.aspx", true);
    req.send(null);
}
通过readyState属性判断请求的状态,当readyState = 4时,表示收到全部响应数据,属性值的定义如下:
readyState值:0 未初始化;尚未调用open()方法;1 启动;尚未调用send()方法;2 已发送;但尚未收到响应;3 接收;已经收到部分响应数据;4 完成;收到全部响应数据

jsonp的产生原因
  1.Ajax直接请求普通文件存在跨域无权限访问的问题(静态页、动态页、web服务、wcf只要是跨域请求一律不准)
  2.web的页面上调用js文件是不受跨域的影响(凡拥有src属性的标签都拥有跨域能力script img iframe)
  3.可以判断 现在想通过纯web端(ActiveX控件、服务端代理、H5之Websocket等方式不算)跨域访问数据就只有一种可能,就是在远程服务器上设法把数据装进js格式的文件里,供客户度调用和进一步处理;
  4.json的纯字符数格式可以简洁的描述复杂数据还被js原生支持
  5.web客户端通过与调用脚本一样的方式来调用跨域服务器上动态生成的js格式文件(后缀.json),服务器之所以要动态生成json文件目的把客户端需要的数据装入进去
  6.客户端在对json文件调用成功后获得自己所需的数据剩下的就按照自己需求进行处理和展现,这种获取远程数据的方式非常像ajax其实并一样
  7.为了方便客户端使用数据逐渐形成非正式传输协议jsonp
    该协议的一个要点就是允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住json数据 这样客户端就可以随意定制自己的函数来自动处理返回数据

ajax和jsonp的实质核心、区别联系
  1.ajax和jsonp的调用方式很像,目的一样,都是请求url,然后把服务器返回的数据进行处理,
  2.实质不同
    ajax的核心是通过xmlHttpRequest获取非本页内容
    jsonp的核心是动态添加script标签调用服务器提供的js脚本
  3.区别联系: 不在于是否跨域
    ajax通过服务端代理一样跨域
    jsonp也不并不排斥同域的数据的获取
  4.jsonp是一种方式或者说非强制性的协议
    ajax也不一定非要用json格式来传递数据

v-model实现原理是什么?v-model的使用方法

Vue中Vue-model原理是什么?v-model是Vue用于表单元素上创建双向数据绑定,它本质是一个语法糖,在单向数据绑定的基础上,增加了监听用户输入事件并更新数据的功能。
v-model用于表单数据的双向绑定,其实它就是一个语法糖,这个背后就做了两个操作: 
  1. v-bind绑定一个value属性 
  2. v-on指令给当前元素绑定input事件
自定义组件使用v-model,应该有以下操作: 
  1. 接收一个value prop 
  2. 触发input事件,并传入新值
  在原生表单元素中:  
  相当于 
  
  在自定义组件中 : 
  相当于 
  
  这个时候,inputValue接受的值就是input事件的回调函数的第一个参数,所以在自定义组件中,要实现数据绑定,还需要$emit去触发input的事件。   this.$emit('input', value)

v-model实现原理:
Vue初始化组件时通过genDirectives(el,state)初始化指令。(这里的el已经通过parseHTML将html结构转换成Vue的AST语法树,state是根据用户定义组件的options新建的CodegenState对象)。
当用户在html页面上写了v-model指令进行数据双向绑定,Vue通过state找到model指令对应的方法model(el,dir,_warn),并执行该方法。(这里双!!表示将函数返回结果转换成Boolean类型)

以下数组定义时,输出值分别为?

var [x=1] = [undefined]
var [y=1] = [null]
console.log(x,y);  //1, null

js中isNaN、Number.isNaN,isFinite、Number.isFinite的区别

判断是否是NaN的方法isNaN
全局作用域中,isNaN方法在判断数据的时候,会将数据做类型转换(可以判断字符串,布尔值等类型)
ES6为了纠正数据类型转换的问题,提供了Number.isNaN方法,只能判断数字中的NaN,不会做类型转换
判断数字是有限的方法isFinite
全局作用域中,isFinite可以判断是否是有限的,判断的不够准确(会对字符串,布尔值等做转换)
ES6提供Number.isFinite方法,只能判断数字类型是否是有限的
总结区别: isNaN和isFinite方法都是window对象的方法,他们在判断数据的时候会对数据做类型转换,转换完再判断,所以判断有时候是不准确的。而Number.isNaN和Number.isFinite是es6新出的,对Number对象的拓展方法,它们进行判断的时候不会转化类型,所以判断更准确。
isNaN('abc') => true(判断时进行了类型转化,把‘abc’转化为了NaN)      Number.isNaN('abc') => false(没有进行类型转换)
isFinite('123') => true(判断时进行了类型转化,把‘123’转化为了123)     Number.isFinite('123') => false(没有进行类型转换)
Number.isInteger()判断一个值是否为整数。需要注意,在JavaScript内部,整数和浮点数是同样的储存方法,所以3和3.0被视为同一个值。Number.isInteger(25) //true  Number.isInteger(25.0) //true
Number.parseInt === parseInt // true
Number.parseFloat === parseFloat // true
ES6的Number对象新增了一个常量Number.EPSILON。这个值很小,在控制台下打印:Number.EPSILON;// 2.220446049250313e-16

WebSocket原理及使用场景

WebSocket是一种网络通信协议,很多高级功能都需要它。
因为HTTP协议有一个缺陷:通信只能由客户端发起。
特点:
(1)服务端可以主动推送信息,属于服务器推送技术的一种。
(2)建立在TCP协议之上,服务端的实现比较容易。
(3)与HTTP协议有着良好的兼容性,默认端口也是80和443,并且握手阶段采用HTTP协议,因此握手时不容易屏蔽,能通过各种HTTP代理服务器。
(4)数据格式比较轻量,性能开销小,通信高效。
(5)可以发送文本,也可以发送二进制数据。
(6)没有同源限制,客户端可以与任意服务器通信。
(7)协议标识符是ws(如果加密,则为wss),服务器网址就是URL。
客户端的API
(1)WebSocket构造函数
var ws = new WebSocket(‘ws://localhost:8080’);执行语句之后,客户端就会与服务器进行连接。
(2)webSocket.readyState
readyState属性返回实例对象的当前状态,共有四种:CONNECTING:值为0,表示正在连接。OPEN:值为1,表示连接成功,可以通信了。CLOSING:值为2,表示连接正在关闭。CLOSED:值为3,表示连接已经关闭,或者打开连接失败。
(3)webSocket.onopen
实例对象的onopen属性,用于指定连接成功后的回调函数
ws.onopen = function(){}
如果要指定多个回调函数,可以使用addEventListener方法。
ws.addEventListener(‘open’,function(event){});
(4)webSocket.onclose
实例对象的onclose属性,用于指定连接关闭后的回调函数。
(5)webSocket.onmessage
实例对象的onmessage属性,用于指定收到服务器数据后的回调函数。
注意,服务器数据可能是文本,也可能是二进制数据(blob对象或Arraybuffer对象)
(6)webSocket.send()
实例对象的send()方法用于向服务器发送数据。
(7)webSocket.bufferedAmount
实例对象的bufferedAmount属性,表示还有多少字节的二进制数据没有发送出去,可用来判断发送是否结束。
(8)webSocket.onerror
实例对象的onerror属性,用于指定报错时的回调函数。

最典型的场景就是聊天室,假如用HTTP协议的话,就只能去轮询获取服务端有没有消息了,而用WebSocket的话,服务端有新消息可以自动推送。

WebSocket和Socket的区别与联系
首先,Socket 其实并不是一个协议。它工作在 OSI 模型会话层(第5层),是为了方便大家直接使用更底层协议(一般是 TCP 或 UDP )而存在的一个抽象层。Socket是对TCP/IP协议的封装,Socket本身并不是协议,而是一个调用接口(API)。
Socket通常也称作”套接字”,用于描述IP地址和端口,是一个通信链的句柄。网络上的两个程序通过一个双向的通讯连接实现数据的交换,这个双向链路的一端称为一个Socket,一个Socket由一个IP地址和一个端口号唯一确定。应用程序通常通过”套接字”向网络发出请求或者应答网络请求。
Socket在通讯过程中,服务端监听某个端口是否有连接请求,客户端向服务端发送连接请求,服务端收到连接请求向客户端发出接收消息,这样一个连接就建立起来了。客户端和服务端也都可以相互发送消息与对方进行通讯,直到双方连接断开
WebSocket的使用场景:(共同点就是,高实时性)
1.社交聊天(特点是低延迟,高即时)。2.弹幕(幕需实时显示,需要即时)。3.多玩家游戏 4.协同编辑 5.股票基金实时报价(实时性) 6.体育实况更新 7.视频会议/聊天 8.基于位置的应用(借用移动设备的GPS功能来实现基于位置的网络应用)。 9.在线教育 10.智能家居 

Promise有哪几种状态,各个状态之间是如何进行转换的?

Promise的结构:
class Promise{
    constructor(exector){
        function resolve(){            
        }
        function reject(){          
        }
        exector(resolve,reject)    
    }
    then(){     
    }
}

Promise的三种状态:
pending(未完成)、fulfilled(完成)、rejected(拒绝)。有两种过度:pending -> fulfilled 或者是 pending -> rejected,同一时间只能存在一种状态,且状态一旦改变就不能再变。promise是一个构造函数,promise对象代表一项有两种可能结果(成功或失败)的任务,它还持有多个回调,出现不同结果时分别发出相应回调。
1.初始化,状态:pending
2.当调用resolve(成功),状态:pengding=>fulfilled
3.当调用reject(失败),状态:pending=>rejected
const PENDING = "pending";//Promise会一直保持挂起状态,直到被执行或拒绝。
const FULFULLED = "fulfilled";
const REJECTED = "rejected";
class Promise{
    constructor(exector){
        let self = this;//缓存当前promise对象
        self.status = PENDING;//初始状态,对promise对象调用state(状态)方法,可以查看其状态是“pending"、"resolved"、还是”rejected“
        self.value = undefined;// fulfilled状态时 返回的信息
        self.reason = undefined;// rejected状态时 拒绝的原因
        self.onResolveCallBacks = [];// 存储resolve(成功)状态对应的onFulfilled函数
        self.onRejectCallBacks = [];// 存储rejected(失败)状态对应的onRejected函数
        let resolve = (value) => {//成功
            if(self.status === PENDING){//如果成功则,状态由pending=>fulfilled
                self.status = FULFULLED;
                self.value = value;
                self.onResolveCallBacks.forEach(cb=>cb(self.value));//执行发布
            }
        }
        let reject = (reason) => {//失败
            if(self.status === PENDING){//如果失败,则状态由pending=>rejected
                self.status = REJECTED;
                self.reason = reason;
                self.onRejectCallBacks.forEach(cb=>cb(self.reason));//执行发布
            }
        }
        try{
            exector(resolve,reject)                 
        }catch(e){
            reject(e)
        }
    }
    then(onFulfilled,onRejected){
        let self=this;
        if(self.status === FULFULLED){
            onFulfilled(self.value);//成功值
        }
        if(self.status === REJECTED){
            onFulfilled(self.reason);//拒绝原因
        }
        if(self.status === PENDING){
            self.onResolveCallBacks.push(onFulfilled);//订阅发布
            self.onRejectCallBacks.push(onRejected);//订阅发布
        }
    }
    //promise的决议结果只有两种可能:完成和拒绝,附带一个可选的单个值。如果Promise完成,那么最终的值称为完成值;如果拒绝,那么最终的值称为原因。Promise只能被决议(完成或拒绝)一次。之后再次试图完成或拒绝的动作都会被忽略。
}
3.promise的优缺点
​ 优点:
​ 1.Promise 分离了异步数据获取和业务逻辑,有利于代码复用。
​ 2.可以采用链式写法
​ 3.一旦 Promise 的值确定为fulfilled 或者 rejected 后,不可改变。
​ 缺点:代码冗余,语义不清。
二、为什么用Promise?
1.解决回调地狱
​ 回调地狱:发送多个异步请求时,每个请求之间相互都有关联,会出现第一个请求成功后再做下一个请求的情况。我们这时候往往会用嵌套的方式来解决这种情况,但是这会形成”回调地狱“。如果处理的异步请求越多,那么回调嵌套的就越深。出现的问题:
1.代码逻辑顺序与执行顺序不一致,不利于阅读与维护。
2.异步操作顺序变更时,需要大规模的代码重构。
3.回调函数基本都是匿名函数,bug追踪困难。
const request = url => {
    return new Promise((resolve,reject) => {
        $.get(url,params => {
            resolve(params)
        });
    });
};
request(url).then(params1 => {
    return request(params1.url);   
}).then(params2 => {
    return request(params2.url);
}).then(params3 => {
    console.log(params3);
}).catch(err => throw new Error(err));
2.解决异步
我们都知道js是单线程执行代码,导致js的很多操作都是异步执行(ajax)的,以下是解决异步的几种方式:
​ 1.回调函数(定时器)。
​ 2.事件监听。
​ 3.发布/订阅。
​ 4.Promise对象。(将执行代码和处理结果分开)
​ 5.Generator。
​ 6.ES7的async/await。
三、怎么用Promise?
promise有几种对象方法
1.then方法(异步执行)
当resolve(成功)/reject(失败)的回调函数
//onFulfilled 是用来接收promise成功的值
//onRejected 是用来接收promise失败的原因
promise.then(onFulfilled,onRejected)
2.resolve(成功)
​ 调用onFulfilled
const promise = new Promise((resolve,reject)=>{
    resolve('fulfilled');//状态:pending=>fulfilled
});
promise.then(result =>{//onFulfilled调用
    console.log(result);//'fulfilled'   
},result =>{//onRejected不调用   
})
//注:resolve使用
Promise.resolve('hellow world')相当于
//相当于
const promise = new Promise(resolve=>{
    resolve('hellow world');
})
3.reject(失败)
​ 调用onRejected
const promise = new Promise((resolve,reject)=>{
    reject('rejected');//状态:pending=>rejected    
});
promise.then(result =>{//onFulfilled不调用   
},result =>{//onRejected调用
    console.log(result);//'rejected'   
})
//注:reject使用
Promise.reject('err')相当于
//相当于
const promise = new Promise((resolve,reject)=>{
    reject('err');
});
4.catch
​ 链式写法中可以捕获前面then中发送的异常,这种写法的好处在于先执行promise操作,然后根据返回的结果(成功或失败)来调用onFulfilled(或者onRrejected)函数。
promise.then(onFulfilled).catch(onRrejected); 
5.all
​ Promise.all接收一个promise对象数组为参数,处理并行异步操作会用到,但是需要全部为resolve才能调用。这种情况是几个任务可以并行执行
const promise1= new Promise((resolve,reject)=>{
    resolve('promise1');
});
const promise2= new Promise((resolve,reject)=>{
    resolve('promise2');
});
const promise3= new Promise((resolve,reject)=>{
    resolve('promise3');
});
Promise.all([promise1, promise2, promise3]).then(data => { 
    console.log(data); 
    // ['promise1', 'promise2', 'promise3'] 结果顺序和promise实例数组顺序是一致的
}, err => {
    console.log(err);
});
可以从一个promise对象派生出新的promise对象,我们可以要求代表着并行任务的两个promise对象合并成一个promise对象,由后者负责通知前面的那些任务都已完成。也可以要求代表着任务系列中首要任务的Promise对象派生出一个能代表任务系列中末任务的Promise对象,这样后者就能知道这一系列的任务是否均已完成。
6.race
​ Promise.race接收一个promise对象数组为参数,只要有一个promise对象进入Fulfilled或者Rejected状态的话,就会进行后面的处理。这可以解决多个异步任务的容错
function racePromise(time){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            resolve(time);
        },time)
    })
}
var startDate = Date.now();
Promise.race([
    racePromise(5),
    racePromise(50),
    racePromise(500),
]).then(function(values){
    console.log(values);5
})

generator函数与async函数

generator函数的特点:
1、generator函数又名生成器函数,与普通函数不同,普通函数一旦调用就会执行完,但generator函数中间可以暂停,执行一会歇一会。
2、函数声明时带上 * ,如 function *go(){}。函数内部使用 yield 关键字实现暂停。
3、generator函数函数执行并不会有什么效果,而是返回一个迭代器对象,之后调用迭代器的 next 方法会返回一个值对象。
function *go(a){
    console.log(1);
    let b = yield a;
    console.log(2);
    let c = yield b;
    console.log(3);
    return c;
} 
let iterator = go('aaa');
let r1 = iterator.next();   //第一次next不用传参,没有意义
console.log(r1);    //{ value: 'aaa', done: false }
let r2 = iterator.next('bbb');
console.log(r2)     //{ value: 'bbb', done: false }
let r3 = iterator.next();
console.log(r3)     //{ value: undefined, done: true }
注意:
yield语句只是个标识符,并没有返回值。
yield左边等于等于next()传来的参数值,没传参则为undefined。yield右边的是next()的返回值。
next()返回的对象中done属性值代表当前迭代是否完成

async函数
async函数顾名思义就是异步函数,可以理解为是generator的语法糖。现在应用中异步任务更多使用基于promise与async函数的解决方案。
async函数的几个特点
1、使用async关键字声明函数(如:async function fn(){}).
2、async函数默认返回一个已解决的promise对象,如果手动return其他值,函数会自动return Promise.resolve(其他值)
await
async await是天生一对,async函数中没有出现await那就跟普通函数没什么区别,而await也只能在async函数中使用。
await顾名思义“等待”,await命令后是一个promise对象,如果不是,会被转成一个resolve的promise对象。如果await后面的promise状态是reject的话会抛出异常,所以可以将await语句写在try catch里。
当async函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句,所以调用async函数虽然有等待, 但是并不会导致阻塞, 因为他内部的所有阻塞都封装在promise对象中异步执行.。
与promise方式的简单对比
function promiseFn(){
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('hello');
        }, 2000)
    })
}
//promise方式
promiseFn().then(re => {
    console.log(re);
})
//async await方式
async function fn(){
    let re = await promiseFn();
    console.log(re);
}
fn();

var gen = function* () {
  var f1 = yield readFile('')
  var f2 = yield readFile('')
  console.log(f1.toString())
  console.log(f2.toString())
}
var asyncReadFile = function (){
  var f1 = await readFile('');
  var f2 = await readFile('');
  console.log(f1.toString());
  console.log(f2.toString());
};
asyncReadFile();

 

你可能感兴趣的:(web前端面试,H5离线存储,ajax,js)