原文地址:https://www.hangge.com/blog/cache/detail_1638.html

2015年6月, ES2015(即 ECMAScript 6、ES6) 正式发布。其中 Promise 被列为正式规范,成为 ES6 中最重要的特性之一。

 

1,then()方法

简单来讲,then 方法就是把原来的回调写法分离出来,在异步操作执行完后,用链式调用的方式执行回调函数。
而 Promise 的优势就在于这个链式调用。我们可以在 then 方法中继续写 Promise 对象并返回,然后继续调用 then 来进行回调操作。
 
(1)下面通过样例作为演示,我们定义做饭、吃饭、洗碗(cook、eat、wash)这三个方法,它们是层层依赖的关系,下一步的的操作需要使用上一部操作的结果。(这里使用 setTimeout 模拟异步操作)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
//做饭
function cook(){
    console.log('开始做饭。');
    var p = new Promise(function(resolve, reject){        //做一些异步操作
        setTimeout(function(){
            console.log('做饭完毕!');
            resolve('鸡蛋炒饭');
        }, 1000);
    });
    return p;
}
 
//吃饭
function eat(data){
    console.log('开始吃饭:' + data);
    var p = new Promise(function(resolve, reject){        //做一些异步操作
        setTimeout(function(){
            console.log('吃饭完毕!');
            resolve('一块碗和一双筷子');
        }, 2000);
    });
    return p;
}
 
function wash(data){
    console.log('开始洗碗:' + data);
    var p = new Promise(function(resolve, reject){        //做一些异步操作
        setTimeout(function(){
            console.log('洗碗完毕!');
            resolve('干净的碗筷');
        }, 2000);
    });
    return p;
}

(2)使用 then 链式调用这三个方法:

1
2
3
4
5
6
7
8
9
10
cook()
.then(function(data){
    return eat(data);
})
.then(function(data){
    return wash(data);
})
.then(function(data){
    console.log(data);
});

当然上面代码还可以简化成如下:

1
2
3
4
5
6
cook()
.then(eat)
.then(wash)
.then(function(data){
    console.log(data);
});

(3)运行结果如下:

2,reject()方法

上面样例我们通过 resolve 方法把 Promise 的状态置为完成态(Resolved),这时 then 方法就能捕捉到变化,并执行“成功”情况的回调。
而 reject 方法就是把 Promise 的状态置为已失败(Rejected),这时 then 方法执行“失败”情况的回调(then 方法的第二参数)。
 
(1)下面同样使用一个样例做演示
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//做饭
function cook(){
    console.log('开始做饭。');
    var p = new Promise(function(resolve, reject){        //做一些异步操作
        setTimeout(function(){
            console.log('做饭失败!');
            reject('烧焦的米饭');
        }, 1000);
    });
    return p;
}
 
//吃饭
function eat(data){
    console.log('开始吃饭:' + data);
    var p = new Promise(function(resolve, reject){        //做一些异步操作
        setTimeout(function(){
            console.log('吃饭完毕!');
            resolve('一块碗和一双筷子');
        }, 2000);
    });
    return p;
}
 
cook()
.then(eat, function(data){
  console.log(data + '没法吃!');
})

运行结果如下:

(2)如果我们只要处理失败的情况可以使用 then(null, ...),或是使用接下来要讲的 catch 方法。
1
2
3
4
cook()
.then(nullfunction(data){
  console.log(data + '没法吃!');
})

3,catch()方法

(1)它可以和 then 的第二个参数一样,用来指定 reject 的回调

1
2
3
4
5
cook()
.then(eat)
.catch(function(data){
    console.log(data + '没法吃!');
});

(2)它的另一个作用是,当执行 resolve 的回调(也就是上面 then 中的第一个参数)时,如果抛出异常了(代码出错了),那么也不会报错卡死 js,而是会进到这个 catch 方法中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//做饭
function cook(){
    console.log('开始做饭。');
    var p = new Promise(function(resolve, reject){        //做一些异步操作
        setTimeout(function(){
            console.log('做饭完毕!');
            resolve('鸡蛋炒饭');
        }, 1000);
    });
    return p;
}
 
//吃饭
function eat(data){
    console.log('开始吃饭:' + data);
    var p = new Promise(function(resolve, reject){        //做一些异步操作
        setTimeout(function(){
            console.log('吃饭完毕!');
            resolve('一块碗和一双筷子');
        }, 2000);
    });
    return p;
}
 
cook()
.then(function(data){
    throw new Error('米饭被打翻了!');
    eat(data);
})
.catch(function(data){
    console.log(data);
});

运行结果如下:

这种错误的捕获是非常有用的,因为它能够帮助我们在开发中识别代码错误。比如,在一个 then() 方法内部的任意地方,我们做了一个 JSON.parse() 操作,如果 JSON 参数不合法那么它就会抛出一个同步错误。用回调的话该错误就会被吞噬掉,但是用 promises 我们可以轻松的在 catch() 方法里处理掉该错误。
 
(3)还可以添加多个 catch,实现更加精准的异常捕获。
1
2
3
4
5
6
7
8
9
10
11
somePromise.then(function() {
 return a();
}).catch(TypeError, function(e) {
 //If a is defined, will end up here because
 //it is a type error to reference property of undefined
}).catch(ReferenceError, function(e) {
 //Will end up here if a wasn't defined at all
}).catch(function(e) {
 //Generic catch-the rest, error wasn't TypeError nor
 //ReferenceError
});
 

4,all()方法

Promise 的 all 方法提供了并行执行异步操作的能力,并且在所有异步操作执行完后才执行回调。
 
(1)比如下面代码,两个个异步操作是并行执行的,等到它们都执行完后才会进到 then 里面。同时 all 会把所有异步操作的结果放进一个数组中传给 then。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//切菜
function cutUp(){
    console.log('开始切菜。');
    var p = new Promise(function(resolve, reject){        //做一些异步操作
        setTimeout(function(){
            console.log('切菜完毕!');
            resolve('切好的菜');
        }, 1000);
    });
    return p;
}
 
//烧水
function boil(){
    console.log('开始烧水。');
    var p = new Promise(function(resolve, reject){        //做一些异步操作
        setTimeout(function(){
            console.log('烧水完毕!');
            resolve('烧好的水');
        }, 1000);
    });
    return p;
}
 
Promise
.all([cutUp(), boil()])
.then(function(results){
    console.log("准备工作完毕:");
    console.log(results);
});

(2)运行结果如下:

5,race()方法

race 按字面解释,就是赛跑的意思。race 的用法与 all 一样,只不过 all 是等所有异步操作都执行完毕后才执行 then 回调。而 race 的话只要有一个异步操作执行完毕,就立刻执行 then 回调。
注意:其它没有执行完毕的异步操作仍然会继续执行,而不是停止。
 
(1)这里我们将上面样例的 all 改成 race
1
2
3
4
5
6
Promise
.race([cutUp(), boil()])
.then(function(results){
    console.log("准备工作完毕:");
    console.log(results);
});
 
(2)race 使用场景很多。比如我们可以用 race 给某个异步请求设置超时时间,并且在超时后执行相应的操作。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//请求某个图片资源
function requestImg(){
    var p = new Promise(function(resolve, reject){
    var img = new Image();
    img.onload = function(){
       resolve(img);
    }
    img.src = 'xxxxxx';
    });
    return p;
}
 
//延时函数,用于给请求计时
function timeout(){
    var p = new Promise(function(resolve, reject){
        setTimeout(function(){
            reject('图片请求超时');
        }, 5000);
    });
    return p;
}
 
Promise
.race([requestImg(), timeout()])
.then(function(results){
    console.log(results);
})
.catch(function(reason){
    console.log(reason);
});

上面代码 requestImg 函数异步请求一张图片,timeout 函数是一个延时 5 秒的异步操作。我们将它们一起放在 race 中赛跑。

  • 如果 5 秒内图片请求成功那么便进入 then 方法,执行正常的流程。
  • 如果 5 秒钟图片还未成功返回,那么则进入 catch,报“图片请求超时”的信息。

[转]JS - Promise使用详解2(ES6中的Promise)的更多相关文章

  1. Promise入门详解

    异步调用 异步 JavaScript的执行环境是单线程. 所谓单线程,是指JS引擎中负责解释和执行JavaScript代码的线程只有一个,也就是一次只能完成一项任务,这个任务执行完后才能执行下一个,它 ...

  2. ES6,ES2105核心功能一览,js新特性详解

    ES6,ES2105核心功能一览,js新特性详解 过去几年 JavaScript 发生了很大的变化.ES6(ECMAScript 6.ES2105)是 JavaScript 语言的新标准,2015 年 ...

  3. JS - Promise使用详解--摘抄笔记

    第一部分: JS - Promise使用详解1(基本概念.使用优点) 一.promises相关概念 promises 的概念是由 CommonJS 小组的成员在 Promises/A 规范中提出来的. ...

  4. Js apply方法与call方法详解 附ES6新写法

    我在一开始看到javascript的函数apply和call时,非常的模糊,看也看不懂,最近在网上看到一些文章对apply方法和call的一些示例,总算是看的有点眉目了,在这里我做如下笔记,希望和大家 ...

  5. es6的promise用法详解

    es6的promise用法详解 promise 原理 promise是es6的异步编程解决方案, 是es6封装好的对象: 一个promise有三种状态:Pending(进行中).Resolved(已完 ...

  6. 《Node.js开发实战详解》学习笔记

    <Node.js开发实战详解>学习笔记 ——持续更新中 一.NodeJS设计模式 1 . 单例模式 顾名思义,单例就是保证一个类只有一个实例,实现的方法是,先判断实例是否存在,如果存在则直 ...

  7. Js apply 方法 详解

    Js apply方法详解 我在一开始看到JavaScript的函数apply和call时,非常的模糊,看也看不懂,最近在网上看到一些文章对apply方法和call的一些示例,总算是看的有点眉目了,在这 ...

  8. Js apply()使用详解

    Js apply方法详解 我在一开始看到javascript的函数apply和call时,非常的模糊,看也看不懂,最近在网上看到一些文章对apply方法和call的一些示例,总算是看的有点眉目了,在这 ...

  9. Js apply方法详解,及其apply()方法的妙用

    Js apply方法详解 我在一开始看到javascript的函数apply和call时,非常的模糊,看也看不懂,最近在网上看到一些文章对apply方法和call的一些示例,总算是看的有点眉目了,在这 ...

  10. Vue.js 数据绑定语法详解

    Vue.js 数据绑定语法详解 一.总结 一句话总结:Vue.js 的模板是基于 DOM 实现的.这意味着所有的 Vue.js 模板都是可解析的有效的 HTML,且通过一些特殊的特性做了增强.Vue ...

随机推荐

  1. 刷脸支付袭来,WeChat Pay & AliPay争宠,究竟谁能笑到最后?

    移动支付的快速发展,让我们摆脱了对现金的依赖,即使我们出门忘记带现金,那也没关系,我们照样可以通过手机来完成支付.现如今无论是大商场.还是水果摊都支持二维码付款,这也就意味着智慧化的生活正在一步步地向 ...

  2. 最大m子段和

    最大m子段和 定义一串子段s1,s2,s3 ... sn-1,sn 求m段不交叉最大子段和 解:设dp[i][j]代表前j个数分成i段的最大和(包括a[j]) 状态转移方程: dp[i][j]=Max ...

  3. sq分页

    create proc RowNumber @pageindex int,@pagesize int AS BEGIN select * from (select ROW_NUMBER() OVER( ...

  4. python+正则+多进程爬取糗事百科图片

    话不多说,直接上代码: # 需要的库 import requests import re import os from multiprocessing import Pool # 请求头 header ...

  5. Kotlin高阶函数与函数式编程详解

    函数可变参数: 在上一次https://www.cnblogs.com/webor2006/p/11518425.html中学到了可变参考,关于可变参数有如下规则说明: “一个方法中,只允许一个参数为 ...

  6. C# List<T>排序总结

    这里有很多种方法对List进行排序,本文总结了三种方法,但有多种实现. 1.对基础类型排序 方法一: 调用sort方法,如果需要降序,进行反转: List<int> list = new ...

  7. java-we不在esclipse创建servlet之后改名不起作用的问题归纳

    有时候我们不满意类名而去改名,但是改过了之后却发现不能实现它本来该实现的功能了,这是为什么呢,原因就是在2.5里面创建了servlet之后就会在web.xml里生成关于这个servlet的配置,你只是 ...

  8. Spring源码窥探之:声明式事务

    1. 导入驱动,连接池,jdbc和AOP的依赖 <!-- c3p0数据库连接池 --> <dependency> <groupId>c3p0</groupId ...

  9. 使用docker搭建etcd

    下载etcd代码然后拷贝到服务器 来自为知笔记(Wiz)

  10. jsp大附件上传,支持断点续传

    我们平时经常做的是上传文件,上传文件夹与上传文件类似,但也有一些不同之处,这次做了上传文件夹就记录下以备后用. 这次项目的需求: 支持大文件的上传和续传,要求续传支持所有浏览器,包括ie6,ie7,i ...