##概述Javascript语言的执行环境是"单线程"(single thread)。所谓"单线程",就是指一次只能完成一件任务。若是有多个任务,就必须排队,前面一个任务完成,再执行后面一个任务。前端
这种模式的好处是实现起来比较简单,执行环境相对单纯;坏处是只要有一个任务耗时很长,后面的任务都必须排队等着,会拖延整个程序的执行。常见的浏览器无响应(假死),每每就是由于某一段Javascript代码长时间运行(好比死循环),致使整个页面卡在这个地方,其余任务没法执行。java
JavaScript语言自己并不慢,慢的是读写外部数据,好比等待Ajax请求返回结果。这个时候,若是对方服务器迟迟没有响应,或者网络不通畅,就会致使脚本的长时间停滞。ajax
为了解决这个问题,Javascript语言将任务的执行模式分红两种:同步(Synchronous)和异步(Asynchronous)。"同步模式"就是传统作法,后一个任务等待前一个任务结束,而后再执行,程序的执行顺序与任务的排列顺序是一致的、同步的。这每每用于一些简单的、快速的、不涉及读写的操做。编程
"异步模式"则彻底不一样,每个任务分红两段,第一段代码包含对外部数据的请求,第二段代码被写成一个回调函数,包含了对外部数据的处理。第一段代码执行完,不是马上执行第二段代码,而是将程序的执行权交给第二个任务。等到外部数据返回了,再由系统通知执行第二段代码。因此,程序的执行顺序与任务的排列顺序是不一致的、异步的。promise
如下总结了"异步模式"编程的几种方法,理解它们可让你写出结构更合理、性能更出色、维护更方便的JavaScript程序。##实际应用场景在项目的编辑页面,有不少时候会出现下拉,而且下拉框是经过请求后台获取的数据,可是会出现一种状况你们可能有遇到过,就是下拉框回填不成功,可能你们已经都清楚了缘由就是由于:当请求的详情信息还没返回,请求的下拉接口却已经先返回来了,说直白一点,就是程序的执行前后顺序问题。那么怎么解决这种问题呢?##常见的解决方案###1.用延时来推测结果大概何时!浏览器
var result=ajax(url); setTimeout(function(result){ console.log(result); },400);
优势:几乎无弊端:尽可能可能设置长时间延时,不然,咱们将会操做一个undefined的result,能够说这是一种最不推荐而且反对的写法###2.回调函数!js最多见的一种规定程序执行的前后顺序的处理就是采用回调函数,可能java的同窗不是很明白,其实不少地方都应用到了,好比:ajax的成功以后调用success方法,失败调用error方法,这种就叫回调函数,在某个时间点,数据返回来了,就执行。因此,一般遇到实际场景就会采用回调函数的写法,把第二个ajax写在第一个ajax的success里面,等第一个ajax请求返回结果后,在执行第二个。这种方法俗称函数嵌套。能解决这种状况。可是既然叫函数嵌套,嵌套二字不免让人感受冗余,没错。服务器
ajax(url0,function(result0){ ajax(result0.url1,function(result1){ ajax(result1.url2,function(result2){ console.log(result2); }); }); });
若是嵌套有3个甚至更多,那就出现了回调地狱(Callback Hell)问题。如何规避这种问题呢?答案是就是:promise/a+规范,下面咱们看一下promise/a+规范在了解promise以前咱们先来了解一个链式写法;##链式写法链式写法也是咱们在使用jQuery时候常见的一种,网络
$('#tab').eq($(this).index()).show().siblings().hide();
没错,这个就是咱们所谓的链式写法,只是你们不知道书名而已;之因此叫链式写法,不难看出咱们在一个元素上作的全部jQuery处理均可以一直 "." 下去, 为何能这样,由于jQuery源码封装的时候,每一个方法都返回this(jQuery)。dom
var obj = { step1:function(){ console.log('a'); return this; }, step2:function(){ console.log('b'); return this; }, step3:function(){ console.log('c'); return this; }, step4:function(){ console.log('d'); return this; } } console.log('-----\n'); obj.step1().step2().step3(); console.log('-----\n'); obj.step4().step2().step1();
执行结果复制到控制台查看。这样的写法是否是看着很爽,那么与咱们要讲的promise有什么关系呢?下面进入主题PromiseES 6中原生提供了Promise对象,Promise对象表明了某个将来才会知道结果的事件(通常是一个异步操做),而且这个事件对外提供了统一的API,可供进一步处理。Promise对象有三种状态,分别是pending-进行中、resolved-已完成、rejected-已失败当Promise的状态由pending转变为resolved或rejected时,会执行相应的方法,而且状态一旦改变,就没法再次改变状态,这也是它名字promise-承诺的由来。Promise的构造函数接受一个函数做为参数,这个函数的两个参数分别是resolve方法和reject方法。若是异步操做成功,就是用resolve方法将Promise对象的状态从“未完成”变为“完成”(即从pending变为resolved),若是异步操做出错,则是用reject方法把Promise对象的状态从“未完成”变为“失败”(即从pending变为rejected)异步
###Promise.prototype.then()Promise的then方法返回的是一个新的Promise对象,因此这样呢,咱们就能链式操做了,同时then方法它包含两个参数方法,分别是已成功resolved的回调和已失败rejected的回调,分别是状态看一个例子吧!
const p = function(){ let num = Math.random(); return new Promise((resolve, reject) => { setTimeout(() => { num > 0.1 ? resolve(num) : reject(num); }, 1000); }) }; const p1 = function(val){ let num = Math.random(); return new Promise((resolve, reject) => { setTimeout(() => { num > 0.01 ? resolve(num) : reject(num); }, 1000); }) }; p().then(val => { console.info(`Status1:fulfilled, value1:${val}`); return p1(val); }, val => { console.info(`Status1:reject,value1:${val}`); }).then(val => { console.info(`Status2:fulfilled, value2:${val}`); }, /*function(val1){console.log(val1); },*/val => { console.info(`Status2:reject,value2:${val}`); })
那么每一个then方法都要写一个成功的方法和失败的方法貌似有点冗余啊,还好,Promise提供了一个catch()方法,.catch()的做用是捕获Promise的错误,与then()的rejected回调做用几乎一致,因为Promise的抛错具备冒泡性质,可以不断传递,这样就可以在下一个catch()中统一处理这些错误。同时catch()也可以捕获then()中抛出的错误,因此建议不要使用then()的rejected回调,而是统一使用catch()来处理错误。因此上面代码改成
p().then(val => { console.info(`Status1:fulfilled, value1:${val}`); return p1(val); }).then(val => { console.info(`Status2:fulfilled, value2:${val}`); }).catch(function(err) { console.log('出错:' + err); // 出错:reject // 最后的catch()方法能够捕获在这一条Promise链上的异常 })
好了!大家下来能够试着去这样用用Promise。
##ES6箭头函数一个常见的问题是,ECMAScript 和 JavaScript 究竟是什么关系?不是很重要,因此直白一点,ECMAScript 和 JavaScript 的关系是,前者是后者的规格,后者是前者的一种实现。而ES6,就是ECMAScript的一个版本而已,于2015年发布初版。
1.具备一个参数的简单函数
var f = v => v; //上面的箭头函数等同于: var f = function(v) { return v; };
2.没有参数的须要用在箭头前加上小括号
//若是箭头函数不须要参数或须要多个参数,就使用一个圆括号表明参数部分。
var f = () => 5; // 等同于 var f = function () { return 5 };
3.多个参数须要用到小括号,参数间逗号间隔,例如两个数字相加
//若是箭头函数不须要参数或须要多个参数,就使用一个圆括号表明参数部分。 var sum = (num1, num2) => num1 + num2; // 等同于 var sum = function(num1, num2) { return num1 + num2; };
4.函数体多条语句须要用到大括号
var add = (a, b) => { if (typeof a == 'number' && typeof b == 'number') { return a + b } else { return 0 } }
5.返回对象时须要用小括号包起来,由于大括号被占用解释为代码块了
var getHash = arr => {({ name: 'Jack', age: 33 })}
再多啰嗦一个东西:解构赋值
requestLogin(loginParams).then(data => { this.logining = false; let { msg, code, user, list} = data; if (!list.length) { this.$message({ message: '登陆失败', type: 'error' }); } }); //等同于 requestLogin(loginParams).then(data => { var msg=data.msg; var list=data.list; var code=data.code; if (!list.length) { this.$message({ message: '登陆失败', type: 'error' }); } });
是否是以为仍是比较方便简洁些了。