Promise整理

在开发过程中,我们经常需要处理异步的情况,开发人员对异步的处理方式也从轮询到回调,再到现在的Promise。于是,我打算对Promise整理一番。

Promise类似于XMLHttpRequest,通过构造函数Promise来创建一个新Promise对象作为接口。要想创建一个promise对象,可以使用new来调用Promise的构造器实例化:

var promise=new Promise(function(resolve,reject){
    //异步处理
    //处理结束后,调用resolve或reject
})

Promise的状态

用new Promise实例化的对象有三个状态:

  • Fulfilled:resolve(成功)时,此时会调用onFulfilled;
  • Rejected:reject(失败)时,此时会调用onRejected;
  • Pending:既不是resolve也不是reject的状态,也就是promise对象刚被创建后的初始化状态。

Promise.resolve

Promise.resolve(value)可以认为是以下代码的语法糖:

new Promise(function(resolve){
    resolve(value); 
});

在这段代码中的resolve(value);会让这个promise对象立即进入确定(即resolved)状态,并将value传递给后面then里所指定的onFulfilled函数。

方法Promise.resolve(value);的返回值也是一个promise对象,所以我们可以像下面那样接着对其返回值进行.then调用:

Promise.resolve(value).then(function(value){
    console.log(value);
})

Promise.resolve方法的另一个作用就是将thenable对象转换为promise对象。

thenable,简单来说是一个非常类似于promise的东西,它指一个具有.then方法的对象。例如jQuery.ajax(),它的返回值是一个具有.then方法的jqXHR Object对象,这个对象继承了来自Deferred Object的方法和属性。但是Deferred Object并没有遵循Promises/A+或ES6 Promises标准,所以即使看上去这个对象转换成了一个promise对象,但是二者的then方法机制不同。

将thenable对象转换成promise对象:

var promise=Promise.resolve($.ajax(...));
promise.then(function(value){
    console.log(value);
});

简单总结一下Promise.resolve方法的话,可以认为它的作用就是将传递给它的参数填充(Fulfilled)到promise对象后并返回这个promise对象,它的参数主要分为以下三类:

  1. 接收到promise对象参数时:返回该promise对象
  2. 接收到thenable类型的对象时:返回一个新的promise对象,该对象具有一个then方法;
  3. 接收到其他类型的参数(或者参数为空)时:返回一个将该参数作为值的新promise对象

另外,调用resolve或reject并不会终结Promise的参数函数的执行:

var promise = new Promise(function (resolve){
    console.log("promise1"); 
    resolve(42);
    console.log("promise2"); 
});
promise.then(function(value){
    console.log(value);
});

结果:

上面代码中,虽然在调用了 resolve(42)之后打印promise2,但是实际上promise2先打印出来。

Promise.reject

Promise.reject(error)可以认为是以下代码的语法糖:

new Promise(function(resolve,reject){
    reject(new Error("出错了")); 
});

Promise只能进行异步操作?

promise是同步的,.then是异步的(规定:Promise只能使用异步调用方式):

var promise = new Promise(function (resolve){
    console.log("inner promise"); 
    resolve(42);
});
promise.then(function(value){
    console.log(value);
});
console.log("outer promise"); 

结果:

依照结果来看,打印出"inner promise"后紧接着打印出了"outer promise",最后才调用.then方法打印出value。所以为了避免同步调用和异步调用同时存在导致的混乱,即使.then方法可以立即调用(即同步调用),Promise也会以异步的方式调用该回调函数,这是在Promise设计上的规定方针

所以这个方针也告诉我们,如果我们的回调函数可能会同步调用,也可能异步调用,最好选择同一使用异步调用的方式。例如,将代码:

function onReady(fn) {
    var readyState = document.readyState;
    if (readyState === 'interactive' || readyState === 'complete') {
        fn();    // 注意这里
    } else {
        window.addEventListener('DOMContentLoaded', fn);
    }
}
onReady(function () {
    console.log('DOM fully loaded and parsed');
});
console.log('==Starting==');

中的fn改为:

setTimeout(fn, 0);

这样,同步的fn回调就变为了异步的fn回调。

Promise.all

Promise.all接收一个promise对象的数组作为参数,当这个数组里的所有promise对象全部变为resolve或reject状态时,它才会去调用.then方法,并且.then方法中的的执行结果的参数顺序与all()中各promise对象的顺序一致。

举例:

var promise1=ajax({...});
var promise2=ajax({...});
Promise.all([promise1,promise2]).then(fn);

只有promise1和promise2都完成了,才会去调用then方法。

注意点:传递给Promise.all的promise并不是一个个顺序执行的,而是同时开始、并行执行的。对于上面的例子,promise1和promise2同时开始、并行执行。

Promise.race

Promise.race接收一个promise对象的数组作为参数,当这个数组里的所有promise对象中只要有一项变为resolve或reject状态时,它就会去调用.then方法,并且.then方法中的的执行结果的参数即为该promise对象的回调参数。

举例:

var promise1=ajax({...});
var promise2=ajax({...});
Promise.race([promise1,promise2]).then(fn);

只要promise1和promise2其中有一个完成,就会去调用then方法。

注意点:当Promise.race中的第一个promise对象变为确定(fulfilled)状态后,它之后的promise对象会继续运行,不会取消或者中断。对于上面的例子,只要promise1或者promise2其中某一个变为确定态,就会去调用then方法。

其他注意点

  1. .catch是语法糖,promise.catch(function(error){...})等价于promise.then(undefined,function(error){...})

  2. 每次调用then都会返回一个新创建的promise对象

  3. 使用promise.then(onFulfilled, onRejected)时,如果onFulfilled中发生异常,在onRejected中是捕获不到这个异常的;而在promise.then(onFulfilled).catch(onRejected)中,.then中的异常能在.catch中捕获。

  4. 使用reject而非throw

由于个人水平有限,博客错误之处,烦请指正!

参考资料:
1、JavaScript Promise迷你书
2、Promise/A+规范

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345

推荐阅读更多精彩内容

  • Promise 对象 Promise 的含义 Promise 是异步编程的一种解决方案,比传统的解决方案——回调函...
    neromous阅读 8,698评论 1 56
  • 本文适用的读者 本文写给有一定Promise使用经验的人,如果你还没有使用过Promise,这篇文章可能不适合你,...
    HZ充电大喵阅读 7,296评论 6 19
  • 前言 本文旨在简单讲解一下javascript中的Promise对象的概念,特性与简单的使用方法。并在文末会附上一...
    _暮雨清秋_阅读 2,183评论 0 3
  • title: promise总结 总结在前 前言 下文类似 Promise#then、Promise#resolv...
    JyLie阅读 12,225评论 1 21
  • Promise学习(上): 资料: JavaScript Promise迷你书 原著:azu / 翻译:liubi...
    你隔壁的陌生人阅读 557评论 0 1