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)
        })
    });
}

Q.E.D.

知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议

脸朝大海, 春暖花开 ----江大脸