Promise
Promise 是异步编程的一种解决方案。
Promise
对象有以下两个特点。
(1)对象的状态不受外界影响。Promise
对象代表一个异步操作,有三种状态:pending
(进行中)、fulfilled
(已成功)和rejected
(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise
这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。
(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise
对象的状态改变,只有两种可能:从pending
变为fulfilled
和从pending
变为rejected
。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise
对象添加回调函数,也会立即得到这个结果。这与事 件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。
es5执行异步操作:
{ // 基本定义 let ajax=function(es5func){ console.log('执行'); setTimeout(function () { es5func&&es5func.call() }, 1000); }; ajax(function(){ console.log('timeout1'); }) } //执行 // timeout1
Promise
{ let ajax=function(){ console.log('执行2'); return new Promise(function(resolve,reject){ setTimeout(function () { resolve() }, 1000); }) }; ajax().then(function(){ console.log('timeout2'); }) } //执行2 // timeout2
多个异步操作
{ let ajax=function(){ console.log('执行3'); return new Promise(function(resolve,reject){ resolve() }) }; ajax() .then(function(){ return new Promise(function(resolve,reject){ resolve() }); }) .then(function(){ console.log('timeout3'); }) }
Promise 新建后就会立即执行。
let promise = new Promise(function(resolve, reject) { console.log('Promise'); resolve(); }); promise.then(function() { console.log('resolved.'); }); console.log('Hi!'); // Promise // Hi! // resolved
then
方法可以接受两个回调函数作为参数。第一个回调函数是Promise
对象的状态变为resolved
时调用,第二个回调函数是Promise
对象的状态变为rejected
时调用。其中,第二个函数是可选的,不一定要提供。这两个函数都接受Promise
对象传出的值作为参数。
function timeout(ms) { return new Promise((resolve, reject) => { setTimeout(resolve, ms, 'done'); }); } timeout(100).then((value) => { console.log(value); }); //done
捕获错误:.catch()
func(参数).then(function(value) { // ... }).catch(function(error) { // 处理func和 前一个回调函数运行时发生的错误 console.log('发生错误!', error); });
{ let ajax=function(num){ console.log('执行4'); return new Promise(function(resolve,reject){ if(num>5){ resolve() }else{ throw new Error('出错了') } }) } ajax(6).then(function(){ console.log('log',6); }).catch(function(err){ console.log(err); }); ajax(3).then(function(){ console.log('log',3); }).catch(function(err){ console.log('catch',err); }); } //执行4 // 执行4 // log 6 // Error: 出错了 // at <anonymous>:8:15 // at new Promise (<anonymous>) // at ajax (<anonymous>:4:12) // at <anonymous>:19:3
Promise.all()
Promise.all
方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。
只有Promise.all()中所有实例的状态都变成fulfilled
,或者其中有一个变为rejected
,才会调用Promise.all
方法后面的回调函数。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <script type="text/javascript"> { // 所有图片加载完再添加到页面 function loadImg(src){ return new Promise((resolve,reject)=>{ let img=document.createElement('img'); img.src=src; img.onload=function(){ resolve(img); } img.onerror=function(err){ reject(err); } }) } function showImgs(imgs){ imgs.forEach(function(img){ document.body.appendChild(img); }) } Promise.all([ loadImg('http://img.mukewang.com/52da54ed0001ecfa04120172.jpg'), loadImg('http://img.mukewang.com/52da54ed0001ecfa04120172.jpg'), loadImg('http://img.mukewang.com/52da54ed0001ecfa04120172.jpg') ]).then(showImgs); } </script> </body> </html>
Promise.race()
Promise.race
方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。
只要Promise.race所有实例中有一个实例率先改变状态,状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给回调函数。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <script type="text/javascript"> { // 有一个图片加载完就添加到页面 function loadImg(src){ return new Promise((resolve,reject)=>{ let img=document.createElement('img'); img.src=src; img.onload=function(){ resolve(img); } img.onerror=function(err){ reject(err); } }) } function showImgs(img){ let p=document.createElement('p'); p.appendChild(img); document.body.appendChild(p) } Promise.race([ loadImg('http://img.mukewang.com/52da54ed0001ecfa04120172.jpg'), loadImg('http://img.mukewang.com/52da54ed0001ecfa04120172.jpg'), loadImg('http://img.mukewang.com/52da54ed0001ecfa04120172.jpg') ]).then(showImgs) } </script> </body> </html>
用promise封装ajax请求
function getJSON (url) { return new Promise( (resolve, reject) => { var xhr = new XMLHttpRequest(); xhr.open('GET', url, true); xhr.onreadystatechange = function () { if (xhr.readyState === 4) { if (xhr.status === 200) { resolve(xhr.responseText, xhr); } else { var resJson = { code: this.status, response: this.response }; reject(resJson, this); } } } xhr.send(); }) }