或许我们已经看出些什么了,实例化出一个Promise,根据ret的布尔值决定是否resolve执行正常回调流程还是执行reject回调走意外的流程,显然ret是true,当执行resolve时,传递了一个字符串参数true,可以看到实例化出来的Promise对象后面链式调用了很多then方法,其实then方法同样也是有resolve和reject两个回调参数,上层的Promise执行的回调传递到then函数中,Promise的resolve传递到then的resolve,同理reject也一样,之后我们发现最后一个catch函数,这是一个捕抓异常的函数,当流程发生异常,我们可以在catch方法中获取异常并处理。
可能解释的比较羞涩,看看下面例子,发出一个网络请求,获取用户头像,再把用户头像插入DOM中,再睡眠2000ms,再打印出SUCCESS,再睡眠3000ms,在alert出ERROR,再休眠1000ms,最后打印出ERROR。这...看起来有点丧心病狂,但只是举个例子:
$.get('/user/1/avatar', (data) => { $('#avatar img').attr('src', data['avatar']); setTimeout(() => { console.log('SUCCESS'); setTimeout(() => { alert('ERROR'); setTimeout(() => { console.log('ERROR'); }, 1000); }, 3000) }, 2000); });
一共有四个回调函数,也不算多,如果有十几个回调呢?直至是噩梦呀。一层一层的嵌套,看起来已经眼花了。那么Promise能做些什么改变呢?
function sleep(time) { return new Promise((resolve) => { setTimeout(resolve, time); }); } new Promise((resolve) => { $.get('/user/1/avatar', resolve); }).then((avatar) => { $('#avatar img').attr('src', avatar); }).then(() => { return sleep(2000); }).then(() => { console.log('SUCCESS'); return sleep(3000); }).then(() => { alert('ERROR'); return sleep(1000); }).then(() => { console.log('ERROR'); });
额...看起来怎么使用Promise代码量比不使用的还多呀。不要介意,嘿嘿,可能是我个人封装不精,但是使用Promise的代码可读性确实比上面的要好很多,而且我们不必写一堆的嵌套回调函数,在享受使用同步写法的待遇,又可以得到异步的功能,两全其美,这样的写法还是比较符合日常的思维方式,哈哈。
看看小程序中怎么应用,在小程序项目的app.js中,我们经常看见这段代码:
App({ getUserInfo:function(cb){ var that = this if(this.globalData.userInfo){ typeof cb == "function" && cb(this.globalData.userInfo) }else{ wx.login({ success: function () { wx.getUserInfo({ success: function (res) { that.globalData.userInfo = res.userInfo typeof cb == "function" && cb(that.globalData.userInfo) } }) } }) } } });
这是个方法是获取当前用户的信息,首先先检查globalData对象中有没有缓存有userInfo对象(存储用户的信息),如果有就返回给用户传进来的回掉函数,否则就请求接口获取用用户信息,获取用户信息之前,微信小程序要求先调用wx.login认证,才能调用wx.getUserInfo接口。
看的出代码的层次已经有点深了,我们可以用Promise来简化一下(-_-|| 说的有点夸张,实际上这点嵌套还是可以的)
wx.getUserInfo和wx.login这两个接口都用共同的属性success和fail,我们可以封装起来:
/** * @param {Function} func 接口 * @param {Object} options 接口参数 * @returns {Promise} Promise对象 */ function promiseHandle(func, options) { options = options || {}; return new Promise((resolve, reject) => { if (typeof func !== 'function') reject(); options.success = resolve; options.fail = reject; func(options); }); } App({ getUserInfo(cb) { if (typeof cb !== "function") return; let that = this; if (that.globalData.userInfo) { cb(that.globalData.userInfo); } else { promiseHandle(wx.login) .then(() => promiseHandle(wx.getUserInfo)) .then((res) => { that.globalData.userInfo = res.userInfo; cb(that.globalData.userInfo); }) .catch((err) => { log(err); }); } } });
可以看出,使用了Promise之后,代码简洁了不少,层次深度也降低了不少,好家伙,很管用!
其实本次代码中的回调嵌套很少的,为了尽量使用到ES6的新特性,少量的回调嵌套也使用了Promise处理。
介绍了那么多,主要了为了还不了解ES6的读者能够预热一下知识,为后面的案例做好准备,当然,肯定有同学已经对ES6了如指掌,本人也是刚刚学习,欢迎指正错误。
思路
在开工之前,我们先理一下思路,一个普通的日历显示功能应该怎么做,该怎样入手。
日期
获取日期相关的信息,肯定用到Date对象。
let date = new Date(); let day = date.getDate(); //当月的天 let month = date.getMonth() + 1; //月份,从0开始 let year = date.getFullYear(); //年份
我们需要知道当前展示月份的天数。
let dayCount = new Date(currentYear, currentMonth, 0).getDate();