本文实例讲述了ES6中Promise的使用方法。分享给大家供大家参考,具体如下:
在javascript中,代码是单线程执行的,对于一些比较耗时的IO操作,都是通过异步回调函数来实现的。
但是这样会存在一个问题,当下一个的操作需要上一个操作的结果时,我们只能把代码嵌到上一个操作的回调函数里,这样一层嵌一层,最终形成回调地狱。
$.get('/login.php', function (login) { $.get('/user.php', function (user) { $.get('/info.php', function (info) { //代码就这样一层嵌一层,不够直观,维护也麻烦 }); }); });
为了解决这种问题,ES6中就提供了Promise方法来解决这种问题。
Promise是一个构造函数,通过它,我们可以创建一个Promise实例对象。
let p = new Promise(function (resolve, reject) { setTimeout(() => { console.log('OK'); resolve('OK'); }, 1000); });
Promise构造函数接受一个函数作为参数,这个函数有两个参数,resolve和reject。
resolve函数是将Promise的状态设置为fulfilled(完成),reject函数是将Promise的状态设置为rejected(失败)。
上述代码,我们并没有进行任何调用,当运行时,间隔1秒后输出了'OK'。所以这里需要注意,我们通常使用Promise时,需要在外层再包裹一层函数。
let p = function () { return new Promise(function (resolve, reject) { setTimeout(() => { console.log('OK'); resolve('OK'); }, 1000); }); }; p();
上面的代码p();返回的是一个Promise实例对象,Promise对象上有 then() , catch() , finally() 方法。
then方法有两个参数,onFulfilled和onRejected,都是函数。
onFulfilled用于接收resolve方法传递过来的数据,onRejected用于接收reject方法传递过来的数据。
let p = function () { return new Promise(function (resolve, reject) { setTimeout(() => { if (Math.random() > 0.5) { resolve('OK'); } else { reject('ERR'); } }, 1000); }); }; p().then(function (data) { console.log('fulfilled', data); }, function (err) { console.log('rejected', err); });
then()方法总是会返回一个Promise实例,这样我们就可以一直调用then()。
在then方法中,你既可以return 一个具体的值 ,还可以return 一个Promise对象。
如果直接return的是一个数据,那then方法会返回一个新Promise对象,并以该数据进行resolve。
let p = function () { return new Promise(function (resolve, reject) { resolve(1); }); }; p().then(function (data) { console.log(`第 ${data} 次调用`); //注意这里直接返回的值 //then会创建一个新的Promise对象,并且以返回的值进行resolve //那么该值会被下面的then方法的onFulfilled回调拿到 return ++data; }).then(function (data) { console.log(`第 ${data} 次调用`); return ++data; }).then(function (data) { console.log(`第 ${data} 次调用`); return ++data; });
如果返回的是一个Promise对象,请看下面代码。
let p = function () { return new Promise(function (resolve, reject) { resolve(1); }); }; p().then(function (data) { console.log(`第 ${data} 次调用`); return new Promise(function (resolve, reject) { resolve(++data); }); }).then(function (data) { console.log(`第 ${data} 次调用`); return new Promise(function (resolve, reject) { resolve(++data); }); }).then(function (data) { console.log(`第 ${data} 次调用`); return new Promise(function (resolve, reject) { resolve(++data); }); });
其实效果与直接返回值的是一样的。
即然then()可以进行链式操作,那我们最早之前的回调地狱写法,就可以通过它进行改进了。
function login() { return new Promise(function (resolve, reject) { $.get('/login.php', function (result) { resolve(result); }); }); } function user(data) { return new Promise(function (resolve, reject) { $.get('/user.php', function (result) { resolve(result); }); }); } function info(data) { return new Promise(function (resolve, reject) { $.get('/info.php', function (result) { resolve(result); }); }); } login().then(function (data) { console.log('处理login'); //把login异步处理获取的数据,传入到下一个处理中。 return user(data); }).then(function (data) { console.log('处理user'); //把user异步处理获取的数据,传入到下一个处理中。 return info(data); }).then(function (data) { console.log('处理info'); });
这样修改后,回调地狱层层嵌套的结构就变的清晰多了。上述代码是伪代码。
Promise对象还有一个catch方法,用于捕获错误,该方法与 then(null, onRejected) 等同,是一个语法糖。
let p = function () { return new Promise(function (resolve, reject) { resolve('开始'); }); }; p().then(function (data) { console.log('1'); return new Promise(function (resolve, reject) { reject('错误1'); }); }).then(function (data) { console.log('2'); return new Promise(function (resolve, reject) { reject('错误2'); }); }).then(function (data) { console.log('3'); return new Promise(function (resolve, reject) { reject('错误3'); }); }).catch(function (reason) { console.log(reason); });
注意,一旦操作中有错误发生,则会进入到catch中,后面的操作将不再执行。
Promise对象内部自带了try catch,当代码运行时错误,会自动以错误对象为值reject,并最终被catch捕获。
let p = function () { return new Promise(function (resolve, reject) { resolve('开始'); }); }; p().then(function (data) { //注意这里打印了一个未定义的变量 console.log(a); }).catch(function (reason) { //这里会捕获到错误 console.log('rejected'); console.log(reason); });
Promise还提供了,all(),race(),reject(),resolve()等在构造函数上的方法,调用这些方法并不需要实例化对象。
all()方法,可以让我们并行的执行异步操作,直到所有操作完成了,才执行回调。
function fn1() { return new Promise(function (resolve, reject) { setTimeout(function () { resolve('fn1'); }, 1000); }); } function fn2() { return new Promise(function (resolve, reject) { setTimeout(function () { resolve('fn2'); }, 2000); }); } function fn3() { return new Promise(function (resolve, reject) { setTimeout(function () { resolve('fn3'); }, 3000); }); } //all会等待所有操作完成,会把所有操作的结果放到一个数组中,传给then。 Promise.all([fn1(), fn2(), fn3()]).then(function (data) { console.log(data); });
race()方法是谁先处理完,就以谁为准,把最先处理完的结果传给then。
function fn1() { return new Promise(function (resolve, reject) { setTimeout(function () { resolve('fn1'); }, 1000); }); } function fn2() { return new Promise(function (resolve, reject) { setTimeout(function () { resolve('fn2'); }, 2000); }); } function fn3() { return new Promise(function (resolve, reject) { setTimeout(function () { resolve('fn3'); }, 3000); }); } //race是以谁先处理完,就以谁为准,fn1最先处理完,那fn1的结果会传给then //注意这里fn2和fn3还是会执行,不过不会进入then了 Promise.race([fn1(), fn2(), fn3()]).then(function (data) { console.log(data); });
reject()方法,返回一个带有拒绝原因reason参数的Promise对象。
// Promise.reject('错误') // 等同于 // new Promise(function(resolve, reject) { // reject('错误'); // }); let p = Promise.reject('错误'); p.then(function (data) { }).catch(function (reason) { console.log(reason); });
resolve()方法,根据传入的值返回一个Promise对象。
//如果传入的参数是普通值,则返回一个新Promise对象,并以该值resolve let p1 = Promise.resolve('OK'); p1.then(function (data) { console.log(data); }); //如果传入的参数是一个Promise对象,则原封不动的返回该Promise对象 let obj = new Promise(function (resolve, reject) { resolve('我是Promise对象'); }); let p2 = Promise.resolve(obj); p2.then(function (data) { console.log(data); console.log(p2 === obj); }); //如果传入的参数是一个thenable对象(带有then方法), //会转换成Promise对象,并执行thenable对象的then方法 let then = { then(resolve, reject) { resolve('我是thenable对象'); } } let p3 = Promise.resolve(then); p3.then(function (data) { console.log(data); }); //如果什么参数都不传入,则返回状态为resolved的Promise对象 let p4 = Promise.resolve(); p4.then(function (data) { console.log(data); }).catch(function (reason) { console.log(reason); });
感兴趣的朋友可以使用在线HTML/CSS/JavaScript代码运行工具:http://tools.jb51.net/code/HtmlJsRun测试上述代码运行效果。
更多关于JavaScript相关内容可查看本站专题:《JavaScript操作DOM技巧总结》、《JavaScript页面元素操作技巧总结》、《JavaScript事件相关操作与技巧大全》、《JavaScript查找算法技巧总结》、《JavaScript数据结构与算法技巧总结》、《JavaScript遍历算法与技巧总结》及《JavaScript错误与调试技巧总结》
希望本文所述对大家JavaScript程序设计有所帮助。
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线
暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。
艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。
《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。
更新日志
- 凤飞飞《我们的主题曲》飞跃制作[正版原抓WAV+CUE]
- 刘嘉亮《亮情歌2》[WAV+CUE][1G]
- 红馆40·谭咏麟《歌者恋歌浓情30年演唱会》3CD[低速原抓WAV+CUE][1.8G]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[320K/MP3][193.25MB]
- 【轻音乐】曼托凡尼乐团《精选辑》2CD.1998[FLAC+CUE整轨]
- 邝美云《心中有爱》1989年香港DMIJP版1MTO东芝首版[WAV+CUE]
- 群星《情叹-发烧女声DSD》天籁女声发烧碟[WAV+CUE]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[FLAC/分轨][748.03MB]
- 理想混蛋《Origin Sessions》[320K/MP3][37.47MB]
- 公馆青少年《我其实一点都不酷》[320K/MP3][78.78MB]
- 群星《情叹-发烧男声DSD》最值得珍藏的完美男声[WAV+CUE]
- 群星《国韵飘香·贵妃醉酒HQCD黑胶王》2CD[WAV]
- 卫兰《DAUGHTER》【低速原抓WAV+CUE】
- 公馆青少年《我其实一点都不酷》[FLAC/分轨][398.22MB]
- ZWEI《迟暮的花 (Explicit)》[320K/MP3][57.16MB]