在 掘金上看见一篇写promise的文章,感受做者写的很棒,文章连接在这:八段代码完全掌握 Promise 。看完以后感受学到了不少,因此又从新把JavaScript Promise迷你书(中文版)刷了一遍,如下是我对于promise的理解。es6
所谓Promise,简单说就是一个容器,里面保存着某个将来才会结束的事件(一般是一个异步操做)的结果。从语法上说,Promise 是一个对象,从它能够获取异步操做的消息。Promise 提供统一的 API,各类异步操做均可以用一样的方法进行处理。 —— ECMAScript 6 入门 阮一峰api
Promise对象表明一个异步操做,有三种状态:Pending(准备状态),Fulfilled(成功状态,也称为Resolved状态),Rejected(失败状态)。只有异步操做的结果能够决定promise对象的状态,操做成功后,promise对象由Pending状态转换为Fulfilled状态,此时回调函数会执行 onFulfilled方法。反之,操做失败,promise对象由pending状态转换为Rejected状态,此时回调函数会执行onRejected方法。
以下图所示:数组
var p1 = new Promise(function(resolve,reject){ resolve('resolve'); }); var p2 = new Promise(function(resolve,reject){ reject('reject'); });
p1 返回一个resolved状态,值为resolve的Promise对象promise
Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: "resolve"}
p2 返回一个rejected状态,值为reject的Promise对象异步
Promise {[[PromiseStatus]]: "rejected", [[PromiseValue]]: "reject"}
Promise.then(onFulfilled,onRejected)函数
then方法定义了promise状态变为resolved或者rejected状态以后的回调函数:post
代码示例以下:spa
var p = new Promise(function(resolve, reject){ console.log("create a promise"); resolve("success"); }); console.log("after new Promise"); p.then(function onFulfilled(value){ console.log(value); },function onRejected(error){ console.log(error); });
运行结果以下:code
"create a promise" "after new Promise" "success"
new Promise返回一个resolved状态的promise对象,因此在p.then()方法中调用的是onFulfilled函数。
建立promise时,promise对象中的函数是当即执行的,并非在调用then方法的时候才会去执行,因此首先会输出"create a promise"。可是执行的代码是异步代码,因此"after new Promise"会在"success"以前输出。对象
promise.catch(onRejected);
catch方法捕获了promise运行过程当中的异常。catch与then方法中的onRejected的不一样是,onRejected 函数只能在promise状态变为rejected的时候调用,但catch既能够在promise状态变为rejected的时候调用,又能够捕获第一个onFulfilled方法中出现的错误。
能够参考promise迷你书中的这一段代码:
function throwError(value) { // 抛出异常 throw new Error(value); } // <1> onRejected不会被调用 function badMain(onRejected) { return Promise.resolve(42).then(throwError, onRejected); } // <2> 有异常发生时onRejected会被调用 function goodMain(onRejected) { return Promise.resolve(42).then(throwError).catch(onRejected); } // 运行示例 badMain(function(){ console.log("BAD"); }); goodMain(function(){ console.log("GOOD"); });
在这段代码中,badMain函数中传入onRejected参数,由于Promise.resolve(42)返回一个resolved状态的promise对象(这个api的用法会在下一节中说到),因此会去调用throwError函数,throwError函数中抛出的异常onRejected是捕获不到的,可是catch能够捕获到。
这个方法会根据传进来的参数的不一样,返回不一样的promise对象。
//1.传入的参数是一个普通值 var p1 = Promise.resolve(1);//返回一个将该对象做为值的新promise对象 //2.传入的参数是一个Promise对象 var p2 = Promise.resolve(p1);//返回接收到的promise对象 p1 === p2 //true
在迷你书中介绍了三种状况,除了上面两种以外,还有一种thenable类型的对象的时候,那种这里就不作介绍了,有兴趣的朋友能够本身去看看啊~
这个方法跟Promise.resolve方法同样,会根据传进来的参数的不一样,返回不一样的promise对象。
//1.传入的参数是一个普通值 var p3 = Promise.reject(1);//返回一个将该对象做为值的新promise对象 //2.传入的参数是一个Promise对象 var p4 = Promise.reject(p3);//返回一个新的promise对象 p3 === p4 //false
跟resolve不一样的是,当传入的参数是一个Promise对象的时候,会返回一个rejected状态的新promise对象。
Promise.all接收一个 promise对象的数组做为参数,当这个数组里的全部promise对象所有变为resolve或reject状态的时候,它才会去调用 .then 方法。
示例代码:
var p1 = Promise.resolve(1), p2 = Promise.resolve(2), p3 = Promise.resolve(3); Promise.all([p1, p2, p3]).then(function (results) { console.log(results); // [1, 2, 3] });
Promise.race也是接收一个 promise对象的数组做为参数,参数 promise 数组中的任何一个promise对象若是变为resolve或者reject的话, 该函数就会返回,并使用这个promise对象的值进行resolve或者reject。
var p1 = Promise.resolve(1), p2 = Promise.resolve(2), p3 = Promise.resolve(3); Promise.race([p1, p2, p3]).then(function (value) { console.log(value); // 1 });
这里须要注意的是,虽然在p1resolved以后便执行了then方法,可是并非意味着日后的promise对象不执行了,其余的仍是promise对象仍是要执行的,只是不会再调用then函数。
下面这个demo即可以看出:
var p1 = new Promise(function(resolve,reject){ console.log('I am p1!'); resolve(1); }); var p2 = new Promise(function(resolve,reject){ console.log('I am p2!'); resolve(2); }); var p3 = new Promise(function(resolve,reject){ console.log('I am p3!'); resolve(3); }); Promise.race([p1, p2, p3]).then(function (value) { console.log(value); });
运行结果:
I am p1! I am p2! I am p3! 1
这是个很大的demo,,^-^, 涵盖了不少小知识点,
var p_1 = new Promise(function(resolve,reject){ resolve(1); }); var p_2 = Promise.resolve(1); var p_3 = Promise.reject(1); var p_4 = Promise.resolve(p_2); // 方式1 var p1 = new Promise(function(resolve, reject){ resolve(Promise.resolve('resolve')); }); var p2 = new Promise(function(resolve, reject){ resolve(Promise.reject('reject')); }); var p3 = new Promise(function(resolve, reject){ reject(Promise.resolve('resolve')); }); var p4 = new Promise(function(resolve, reject){ reject(Promise.reject('reject')); }); //方式2 var p1 = Promise.resolve(Promise.resolve('resolve')) var p2 = Promise.resolve(Promise.reject('reject')) var p3 = Promise.reject(Promise.resolve('resolve')) var p4 = Promise.reject(Promise.reject('reject')) //定义回调函数 p1.then( function fulfilled(value){ console.log('fulfilled1: ' + value); }, function rejected(err){ console.log('rejected1: ' + err); } ); p2.then( function fulfilled(value){ console.log('fulfilled2: ' + value); }, function rejected(err){ console.log('rejected2: ' + err); } ); p3.then( function fulfilled(value){ console.log('fulfilled3: ' + value); }, function rejected(err){ console.log('rejected3: ' + err); } ); p4.then( function fulfilled(value){ console.log('fulfilled4: ' + value); }, function rejected(err){ console.log('rejected4: ' + err); } );
采用new Promise 方式建立对象和采用Promise.resolve方法建立出来的对象实际上是同样的,能够把Promise.resolve看作new Promise 的语法糖。只不过须要注意的是,在上面介绍resolve方法的时候说过,若是传入的参数是一个promise对象,会直接返回这个对象,,因此p_2===p_4
输出的是true,可是经过new的方式建立出来的对象都是新建立的,因此new出来的对象跟别的对象都不会全等,即p_1===p_2
会输出false。
两种方式定义的p1,p2,p3,p4都是相同的,从这段代码能够看出,不管是用那种方式建立promise对象,若是使用Promise.resolve方法传入一个新对象,仍是会去‘读取’(可理解为)这个对象的,可是Promise.reject方法传入一个新对象,并不会去‘读取’这个对象,而会直接返回这个这个对象。(这个‘读取’的概念并非promise中的概念,只是个人我的理解,在八段代码完全掌握 Promise 这篇文章中,做者把他解释为‘拆箱’,也是做者的一种让人理解起来更简单的思路,至于promise官方文档中的规定,目前尚未去仔细深刻研究,有时间会去看一下^-^)
从这段代码能够看出,两种方式的执行顺序会有差异,至于为何,今天也查找了不少资料,可是并无找到缘由,有研究过的大神欢迎指导~~