Promise含义
最早是社区提出, 在ES6进入了语言标准,并统一了用法, 原生提供Promise对象. 作为一种异步编程的解决方案, 比传统的解决方案(回调函数
, 事件
)更加合理更加强大,这个网页开发史上关键的时刻,鼓掌!👍
为什么欢呼雀跃
之前我们去做Javascript方面的Coding都为Javascript的单线程吐槽过, 因为它是单线程工作, 也就意味着两端脚本不能同时运行, 必须一个一个排排队的运行, 浏览器中也因为差异性和其他若干N种任务共享一个线程(即使JS它很快). 但是通常情况下Javascript与绘制,更新样式和处理用户操作(如, 控件交互)处于同一队列, 操作其中一项任务就会延迟其他任务.
我们人类是多线程的, 多个手指打字, 一边Coding 一边听歌, 一边开车一边听小说, 唯一一个妨碍可能就是 打喷嚏(打喷嚏所有活动必须都暂停, 认真脸), 所以我们自然不想编写打喷嚏一样的代码. 我们之前都是用回调函数来解决该问题, 如一下 实例:
// 返回文档中匹配指定 CSS 选择器的一个元素。
var imgnode = document.querySelector('.img-1');
img1.addEventListener('load', function() {
// image loaded
});
img1.addEventListener('error', function() {
// argh everything's broken
});
这可不会像打喷嚏那样被打断。 我们获得图像节点、添加几个侦听器,之后 JavaScript 可停止执行,直至其中一个侦听器被调用。
不过遗憾的是,在上例中,事件有可能在我们开始侦听之前就发生了,因此我们需要使用图像的“complete”属性来解决该问题:
var imgnode = document.querySelector('.img-1');
function loaded() {
// image loaded
}
if (img1.complete) {
loaded();
}
else {
img1.addEventListener('load', loaded);
}
img1.addEventListener('error', function() {
// argh everything's broken
});
是不是复杂了很多, 如果加载一组图像,情况会更复杂! 不符合编程美学!
所以事件不一定是最佳方法
- 事件对于一个对象发生多次的事件(如click, keyup, touchstart)非常有用. 因为实际你并不关注在添加监听器之前发生的事情. 但是关系到异步成功/失败.
- 所以Promise ,简单的说它类似一个容器, 里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果. 语法上 Promise 是一个对象, 从这个对象我们可以获取异步操作的消息. Promise 提供统一的API, 各种异步操作都可以用同样的方法进行处理.
Promise 特点
-
对象的状态不受外界的影响. Promise对象代表一个异步操作, 有三种状态:(
pending
,fulfilled
,rejected
). 只有异步操作的结果, 可以决定当前是哪一种状态, 任何其他操作都无法改变这个状态. 这也是Promise 名字由来(n. 许诺,允诺;希望), 表示其他手段无法改变 -
一旦状态改变, 就不会在变, 任何时候都可以得到这个结果. Promise对象的状态改变,只有两种可能: 从
pending
变为fulfilled
和从pending
变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。 -
有了
Promise
对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise
对象提供统一的接口,使得控制异步操作更加容易。 -
Promise
也有一些缺点。首先,无法取消Promise
,一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise
内部抛出的错误,不会反应到外部。第三,当处于pending
状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。 -
如果某些事件不断地反复发生,一般来说,使用
Stream
模式是比部署Promise
更好的选择。
简单版的异步回调
加入我们在写一个不立即返回的函数, 可以等待几秒后返回结果, 一般都是setTimeout :但是这种写法实在是太定制化了,并不好
var testTimeout= function (callback) {
setTimeout(function () {
callback(1);
}, 1000);
};
所以考虑到大多数情况, 代替最简单的返回值和抛出异常, 我们希望函数通常会返回一个对象, 用来表示最后执行成功或者失败的结果, 这就是 Promise
试例
比如我们在做 微信小程序开发的时候, 有个 wx.request
, 这个有点类似 ajax 异步, 但是并没有ajax方便, 'wx.request'是异步请求, js是不会等待它执行完毕再往下执行的, 而且它也没有 asyns 提供可配置的 异步/同步.
所以这个时候就可以搬出Promise了, 我们来包装一下它
const getResultFn = (url, params) => {
return new Promise((resolve, reject) => {
wx.request({
url: httpDoMain + url,
data: params,
success: (res) => resolve(res)
})
});
}