背景
早就在项目中使用过 promise,当时在用 angular 做项目的时候,也探寻过 promise 和 observable 的优劣。但是一直没特别全面的去了解过 promise。现在在看关于 es6 标准的书,还是顺手把它的相关知识总结总结吧。
理解 Promise
Promise,像 observable 一样,是异步编程的一种解决方案。它指的是在一个容器里,保存着未来才会得到的事件结果。也就是说当事件的完成时间是不确定或太长了的时候,我们就可以创建一个Promise来解决问题。比如我们在获取http请求的时候,由于网络或者各种各样的因素,请求的时间比较慢,我们也不能在当前就马上请求到结果,此时我们就可以创建一个promise。
概述
promise对象,正如它的中文翻译一样“承诺”一样,有以下两个特点:
(1)对象状态不受外界影响:一个 promise 对象有:pending→fulfilled→rejected 三种状态。只有异步操作的结果可以决定当前属于哪种状态;
(2)一旦状态改变,就不会再变;promise 对象状态改变,只有:pending→fullilled(失败)和pending→rejected(失败)这两种。只要这两种状态之一产生,就会一直保持这个结果,这时称为 resolved.
正因为有了 promise 对象,我们可以将异步操作以同步流程表达出来,避免了层层嵌套的回调函数。但是当某些事件不断地反复发生,用 observable 比部署 Promise 是更好地选择。
基本用法
下面是一个promise实例:
const promise = new Promise(function (resolve, reject) { if(success) { resolve(value); } else { reject(error) } });
可知,promise的两个参数是 resolve 和 reject;
-
resolve的作用:将 promis 的状态从 pending→fulfilled,在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;
-
rejected的作用:将 promise 的状态从 pending→rejected,在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
promise 实例生成以后,可以用 then 方法分别调用当 resolved 和 rejected 时的回调函数:
let promise = new Promise(function(resolve, reject) { console.log('Promise');// //@1 resolve(); }); promise.then(function() { console.log('hh success');// @2 }); console.log('haha');// @3
输出顺序为 @1→@3→@2; Promise 实例化后立即执行,所以最先输出 ,然后,then 方法指定的回调函数,会在当前脚本所有同步任务执行完才会执行,所以 resolved 最后输出。
其他
- Promise.all():将多个Promise实例,包装成一个新的Promise实例;
const p = Promise.all([p1,p2,p3]); // 数组里的都是promise实例; // 当数组里的promise实例状态都为fulfilled时,p的状态才是fulfilled,他们的返回值组成数组,传递给p的回调函数; // 当数组中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,被传递给p的回调函数。
- promise.race()
const p = Promise.race([p1,p2,p3]); //将多个promise实例,包装成一个新的Promise实例,但是它和promise.all()不一样。 //它指的是,只要p1,p2,p3之中有一个实例率先改变状态,p的状态就跟着改变。 //那个率先改变的Promise实例的返回值,就传递给 p的回调函数。 //race是竞争的意思,由此也可以区分两个。
- promise.resolve():将现有对象转为Promise对象;即返回会一个promise:
const jsPromise = Promise.resolve($.ajax('/whatever.json'));
应用
加载图片:将图片的加载写成一个promise,一旦加载完成,promise的状态会发生变化
const preloadImage = function (path) { return new Promise(function (resolve,reject) { const image = new Image(); image.onload = resolve; image.onerror = reject; image.src = path; }) }