Javascript中的神器——Promise


Posted in Javascript onFebruary 08, 2017

Promise in js

回调函数真正的问题在于他剥夺了我们使用 return 和 throw 这些关键字的能力。而 Promise 很好地解决了这一切。

2015 年 6 月,ECMAScript 6 的正式版 终于发布了。

ECMAScript 是 JavaScript 语言的国际标准,JavaScript 是 ECMAScript 的实现。ES6 的目标,是使得 JavaScript 语言可以用来编写大型的复杂的应用程序,成为企业级开发语言。

概念

ES6 原生提供了 Promise 对象。

所谓 Promise,就是一个对象,用来传递异步操作的消息。它代表了某个未来才会知道结果的事件(通常是一个异步操作),并且这个事件提供统一的 API,可供进一步处理。

Promise 对象有以下两个特点。

(1)对象的状态不受外界影响。Promise 对象代表一个异步操作,有三种状态:Pending(进行中)、Resolved(已完成,又称 Fulfilled)和 Rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是 Promise 这个名字的由来,它的英语意思就是「承诺」,表示其他手段无法改变。

(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise 对象的状态改变,只有两种可能:从 Pending 变为 Resolved 和从 Pending 变为 Rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果。就算改变已经发生了,你再对 Promise 对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。

有了 Promise 对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise 对象提供统一的接口,使得控制异步操作更加容易。

Promise 也有一些缺点。首先,无法取消 Promise,一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise 内部抛出的错误,不会反应到外部。第三,当处于 Pending 状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

var promise = new Promise(function(resolve, reject) {
 if (/* 异步操作成功 */){
 resolve(value);
 } else {
 reject(error);
 }
});
promise.then(function(value) {
 // success
}, function(value) {
 // failure
});

Promise 构造函数接受一个函数作为参数,该函数的两个参数分别是 resolve 方法和 reject 方法。

如果异步操作成功,则用 resolve 方法将 Promise 对象的状态,从「未完成」变为「成功」(即从 pending 变为 resolved);

如果异步操作失败,则用 reject 方法将 Promise 对象的状态,从「未完成」变为「失败」(即从 pending 变为 rejected)。

基本的 api

Promise.resolve()
Promise.reject()
Promise.prototype.then()
Promise.prototype.catch()
Promise.all() // 所有的完成
 var p = Promise.all([p1,p2,p3]);
Promise.race() // 竞速,完成一个即可

进阶

promises 的奇妙在于给予我们以前的 return 与 throw,每个 Promise 都会提供一个 then() 函数,和一个 catch(),实际上是 then(null, ...) 函数,

somePromise().then(functoin(){
  // do something
 });

我们可以做三件事,

1. return 另一个 promise

2. return 一个同步的值 (或者 undefined)

3. throw 一个同步异常 ` throw new Eror('');`

1. 封装同步与异步代码

```
new Promise(function (resolve, reject) {
 resolve(someValue);
 });
```

写成

```
Promise.resolve(someValue);
```

2. 捕获同步异常

new Promise(function (resolve, reject) {
 throw new Error('悲剧了,又出 bug 了');
 }).catch(function(err){
 console.log(err);
 });

如果是同步代码,可以写成

Promise.reject(new Error("什么鬼"));

3. 多个异常捕获,更加精准的捕获

somePromise.then(function() {
 return a.b.c.d();
}).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. 获取两个 Promise 的返回值

1. .then 方式顺序调用
2. 设定更高层的作用域
3. spread

5. finally

任何情况下都会执行的,一般写在 catch 之后

6. bind

somethingAsync().bind({})
.spread(function (aValue, bValue) {
 this.aValue = aValue;
 this.bValue = bValue;
 return somethingElseAsync(aValue, bValue);
})
.then(function (cValue) {
  return this.aValue + this.bValue + cValue;
});

或者 你也可以这样

var scope = {};
somethingAsync()
.spread(function (aValue, bValue) {
 scope.aValue = aValue;
 scope.bValue = bValue;
 return somethingElseAsync(aValue, bValue);
})
.then(function (cValue) {
 return scope.aValue + scope.bValue + cValue;
});

然而,这有非常多的区别,

  • 你必须先声明,有浪费资源和内存泄露的风险
  • 不能用于放在一个表达式的上下文中
  • 效率更低

7. all。非常用于于处理一个动态大小均匀的 Promise 列表

8. join。非常适用于处理多个分离的 Promise

```
var join = Promise.join;
join(getPictures(), getComments(), getTweets(),
 function(pictures, comments, tweets) {
 console.log("in total: " + pictures.length + comments.length + tweets.length);
});
```

9. props。处理一个 promise 的 map 集合。只有有一个失败,所有的执行都结束

```
Promise.props({
 pictures: getPictures(),
 comments: getComments(),
 tweets: getTweets()
}).then(function(result) {
 console.log(result.tweets, result.pictures, result.comments);
});
```

10. any 、some、race

```
Promise.some([
 ping("ns1.example.com"),
 ping("ns2.example.com"),
 ping("ns3.example.com"),
 ping("ns4.example.com")
], 2).spread(function(first, second) {
 console.log(first, second);
}).catch(AggregateError, function(err) {
err.forEach(function(e) {
console.error(e.stack);
});
});;

```

有可能,失败的 promise 比较多,导致,Promsie 永远不会 fulfilled

11. .map(Function mapper [, Object options])

用于处理一个数组,或者 promise 数组,

Option: concurrency 并发现

map(..., {concurrency: 1});

以下为不限制并发数量,读书文件信息

var Promise = require("bluebird");
var join = Promise.join;
var fs = Promise.promisifyAll(require("fs"));
var concurrency = parseFloat(process.argv[2] || "Infinity");
var fileNames = ["file1.json", "file2.json"];
Promise.map(fileNames, function(fileName) {
 return fs.readFileAsync(fileName)
 .then(JSON.parse)
 .catch(SyntaxError, function(e) {
 e.fileName = fileName;
 throw e;
 })
}, {concurrency: concurrency}).then(function(parsedJSONs) {
 console.log(parsedJSONs);
}).catch(SyntaxError, function(e) {
 console.log("Invalid JSON in file " + e.fileName + ": " + e.message);
});

结果

$ sync && echo 3 > /proc/sys/vm/drop_caches
$ node test.js 1
reading files 35ms
$ sync && echo 3 > /proc/sys/vm/drop_caches
$ node test.js Infinity
reading files: 9ms

11. .reduce(Function reducer [, dynamic initialValue]) -> Promise

Promise.reduce(["file1.txt", "file2.txt", "file3.txt"], function(total, fileName) {
 return fs.readFileAsync(fileName, "utf8").then(function(contents) {
 return total + parseInt(contents, 10);
 });
}, 0).then(function(total) {
 //Total is 30
});

12. Time

.delay(int ms) -> Promise
.timeout(int ms [, String message]) -> Promise

Promise 的实现

q

bluebird

co

when

ASYNC

async 函数与 Promise、Generator 函数一样,是用来取代回调函数、解决异步操作的一种方法。它本质上是 Generator 函数的语法糖。async 函数并不属于 ES6,而是被列入了 ES7。

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持三水点靠木!

Javascript 相关文章推荐
Javascript 类与静态类的实现
Apr 01 Javascript
jQuery中操控hidden、disable等无值属性的方法
Jan 06 Javascript
jQuery将所有被选中的checkbox某个属性值连接成字符串的方法
Jan 24 Javascript
javascript强制点击广告的方法
Feb 06 Javascript
jQuery实现Tab选项卡切换效果简单演示
Nov 23 Javascript
Javascript点击其他任意地方隐藏关闭DIV实例
Jun 21 Javascript
Vue.JS入门教程之事件监听
Dec 01 Javascript
js数组实现权重概率分配
Sep 12 Javascript
Node.JS中快速扫描端口并发现局域网内的Web服务器地址(80)
Sep 18 Javascript
web前端vue filter 过滤器
Jan 12 Javascript
jquery实现简单拖拽效果
Jul 20 jQuery
如何在JavaScript中使用localStorage详情
Feb 04 Javascript
jquery获取下拉框中的循环值
Feb 08 #Javascript
Canvas + JavaScript 制作图片粒子效果
Feb 08 #Javascript
jQuery实现标签页效果实战(4)
Feb 08 #Javascript
Angular.JS实现无限级的联动菜单(使用demo)
Feb 08 #Javascript
基于JS实现二维码图片固定在右下角某处并跟随滚动条滚动
Feb 08 #Javascript
jQuery实现级联下拉框实战(5)
Feb 08 #Javascript
webpack入门+react环境配置
Feb 08 #Javascript
You might like
PHP 冒泡排序算法的实现代码
2010/08/08 PHP
php将日期格式转换成xx天前的格式
2015/04/16 PHP
PHP中使用curl入门教程
2015/07/02 PHP
PHP定时执行任务的3种方法详解
2015/12/21 PHP
php变量与JS变量实现不通过跳转直接交互的方法
2017/08/25 PHP
Laravel框架数据库迁移操作实例详解
2020/04/06 PHP
用js实现随机返回数组的一个元素
2007/08/13 Javascript
输入密码检测大写是否锁定js实现代码
2012/12/03 Javascript
jquery链式操作的正确使用方法
2014/01/06 Javascript
JavaScript函数获取事件源的小例子
2014/05/14 Javascript
jQuery 删除或是清空某个HTML元素示例
2014/08/04 Javascript
JavaScript实现搜索框的自动完成功能(一)
2016/02/25 Javascript
jQuery插件Validation快速完成表单验证的方式
2016/07/28 Javascript
基于Vue.js 2.0实现百度搜索框效果
2020/12/28 Javascript
Vue2.0用户权限控制解决方案
2017/11/29 Javascript
浅析Vue项目中使用keep-Alive步骤
2018/07/27 Javascript
JointJS流程图的绘制方法
2018/12/03 Javascript
Nuxt的路由动画效果案例
2020/11/06 Javascript
web.py中调用文件夹内模板的方法
2014/08/26 Python
Python安装Numpy和matplotlib的方法(推荐)
2017/11/02 Python
python如何派生内置不可变类型并修改实例化行为
2018/03/21 Python
浅谈python中get pass用法
2019/03/19 Python
详解python之heapq模块及排序操作
2019/04/04 Python
把vgg-face.mat权重迁移到pytorch模型示例
2019/12/27 Python
浅析Python 抽象工厂模式的优缺点
2020/07/13 Python
Python 保存加载mat格式文件的示例代码
2020/08/04 Python
HTML5 audio标签使用js进行播放控制实例
2015/04/24 HTML / CSS
中国综合网上购物商城:苏宁易购
2016/08/09 全球购物
英国卫浴商店:Ergonomic Design
2019/09/22 全球购物
超市营业员岗位职责
2013/12/20 职场文书
人事部岗位职责范本
2014/03/05 职场文书
捐赠仪式主持词
2014/03/19 职场文书
支部书记四风问题自我剖析材料
2014/09/29 职场文书
宣传稿格式范文
2015/07/23 职场文书
Python - 10行代码集2000张美女图
2021/05/23 Python
VUE之图片Base64编码使用ElementUI组件上传
2022/04/09 Vue.js