本文是借鉴于ac黄的博客。javascript
接触es6也有几个月了,貌似没有系统的去学习过它,老是用到什么,查查什么。今天就说下es6中的promise对象。前端
写前端的同窗都常常遇到这种问题:在多个接口异步请求数据,而后利用这些数据来进行一系列的操做。通常以下实现:java
$.ajax({ url: '......', success: function (data) {
//基于data,才能进行下发操做 $.ajax({ url: '......', success: function (data) { // ...... } }); } });
这样写会致使两个缺点:jquery
在须要多个操做的时候,会致使多个回调函数嵌套,致使代码不够直观,就是常说的 Callback Hell。es6
若是几个异步操做之间并无先后顺序之分(例如不须要前一个请求的结果做为后一个请求的参数)时,一样须要等待上一个操做完成再实行下一个操做。ajax
es6中的Promise对象就来解决这个问题。api
何为Promise对象?数组
一个 Promise 对象能够理解为一次将要执行的操做(经常被用于异步操做),使用了 Promise 对象以后能够用一种链式调用的方式来组织代码,让代码更加直观(解决第1项缺点)。并且因为 Promise.all
这样的方法存在,可让同时执行多个操做变得简单(解决第2项缺点)。promise
你们能够用把下方这段代码贴到浏览器开发模式中的console中运行,看看结果。浏览器
function helloWorld (ready) { return new Promise(function (resolve, reject) { if (ready) { resolve("Hello World!"); } else { reject("Good bye!"); } }); } helloWorld(true).then(function (message) { alert(message); }, function (error) { alert(error); });
结果是,浏览器弹出 “hello world!”.
上面的代码实现的功能很是简单,helloWord
函数接受一个参数,若是为 true
就打印 "Hello World!",若是为 false
就打印错误的信息。helloWord
函数返回的是一个 Promise 对象。
在 Promise 对象当中有两个重要方法————resolve
和 reject
。
resolve
方法可使 Promise 对象的状态改变成成功,同时传递一个参数用于后续成功后的操做,在这个例子当中就是 Hello World! 字符串。
reject
方法则是将 Promise 对象的状态改变为失败,同时将错误的信息传递到后续错误处理的操做。
Fulfilled 能够理解为成功的状态
Rejected 能够理解为失败的状态
Pending 既不是 Fulfilld 也不是 Rejected 的状态,能够理解为 Promise 对象实例建立时候的初始状态
helloWorld 的例子中的 then
方法就是根据 Promise 对象的状态来肯定执行的操做,resolve 时执行第一个函数(onFulfilled),reject 时执行第二个函数(onRejected)。
helloWorld 的例子当中利用了 then(onFulfilld, onRejected)
方法来执行一个任务打印 "Hello World!",在多个任务的状况下 then
方法一样能够用一个清晰的方式完成。
例如:
function printHello (ready) { return new Promise(function (resolve, reject) { if (ready) { resolve("Hello"); } else { reject("Good bye!"); } }); } function printWorld () { alert("World"); } function printExclamation () { alert("!"); } printHello(true) .then(function(message){ alert(message); }) .then(printWorld) .then(printExclamation);
结果是顺序弹出:“Hello”“World”“!”
then
可使用链式调用的写法缘由在于,每一次执行该方法时老是会返回一个 Promise 对象。另外,在 then
onFulfilled 的函数当中的返回值,能够做为后续操做的参数。所以上面的方法能够写为:
function printHello (ready) { return new Promise(function (resolve, reject) { if (ready) { resolve("Hello"); } else { reject("Good bye!"); } }); } printHello(true).then(function (message) { return message; }).then(function (message) { return message + ' World'; }).then(function (message) { return message + '!'; }).then(function (message) { alert(message); });
结果输出是:“Hello World!”。
catch
方法是 then(onFulfilled, onRejected)
方法当中 onRejected
函数的一个简单的写法,也就是说能够写成 then(fn).catch(fn)
,至关于 then(fn).then(null, fn)
。使用 catch
的写法比通常的写法更加清晰明确。
Promise.all
能够接收一个元素为 Promise 对象的数组做为参数,当这个数组里面全部的 Promise 对象都变为 resolve 时,该方法才会返回。
var p1 = new Promise(function (resolve) { setTimeout(function () { resolve("Hello"); }, 3000); }); var p2 = new Promise(function (resolve) { setTimeout(function () { resolve("World"); }, 1000); }); Promise.all([p1, p2]).then(function (result) { console.log(result); // ["Hello", "World"] });
上面的例子模拟了传输两个数据须要不一样的时长,虽然 p2 的速度比 p1 要快,可是 Promise.all
方法会按照数组里面的顺序将结果返回。
平常开发中常常会遇到这样的需求,在不一样的接口请求数据而后拼合成本身所需的数据,一般这些接口之间没有关联(例如不须要前一个接口的数据做为后一个接口的参数),这个时候 Promise.all
方法就能够派上用场了。
Promise.race 和 Promise.all 方法相似,它一样接收一个数组,不一样的是只要该数组中的 Promise 对象的状态发生变化(不管是 resolve 仍是 reject)该方法都会返回。
在浏览器端,一些主流的浏览器都已经可使用 Promise 对象进行开发,在 Node.js 配合 babel 也能够很方便地使用。
若是要兼容旧的浏览器,建议能够寻找一些第三方的解决方案,例如 jQuery 的 $.Deferred。