看完下面文章,你将了解到:

1、什么是Promise?
2、Promise怎样使用以及使用的场景,解决了什么问题
3、ES7较ES6又增加了哪些支撑Promise的语法糖
复制代码

一、Promise

Promise顾名思义,字面理解是"承诺",那承诺什么呢?下面我们就来探究下.
首先,我们先看看Promise是怎么使用的,然后再试着去理解它.
该新特性属于 ECMAScript 2015(ES6)规范.
Promise.prototype 属性表示 Promise构造器的原型.它允许你可以在构造器的原型对象添加属性或方法到所有 Promise 实例上.
复制代码

我们先来看下,Promise.prototype是什么东西?在浏览器打印看下,下图:

可以看到Promise原型上,默认定义了catch,finally,then方法和一个返回的构造函数constructor.

现在我们就来一一举个例子:

    Promise.prototype.constructor();//彩蛋放后Promise.prototype.catch(onRejected)Promise.prototype.then(onFulfilled, onRejected)Promise.prototype.finally(onFinally)
复制代码

1、Promise.prototype.catch(onRejected) 该方法返回一个Promise函数,回调函数添加一个拒绝(rejection),该回调函数处理拒绝的情况.等价与Promise.prototype.then(undefined, onRejected)

感觉还是一脸懵逼是吧,来看下例子: 便于理解,我这里参数就随便定义了success,fail

let promise = new Promise(function(success,fail){throw 'fail';
});
promise.catch(function(resouce){console.dir('then resouce==>'+resouce);
});
等价与Promise.prototype.then(undefined, onRejected)
复制代码

2、Promise.prototype.then(onFulfilled, onRejected) 该方法返回一个Promise函数,回调函数添加一个then,该回调函数最多可添加两个参数,返回成功信息和失败的状态信息.

let promise = new Promise(function(success,fail){success('have successed');
});
promise.then(function(data){console.dir('then data==>'+data);
},function(err_reso){console.dir('then reso==>'+err_reso);
})
复制代码

等价于

let promise = new Promise(function(success,fail){success('have successed');
});
promise.then((data)=>{console.dir('then data==>'+data);
}
).catch((resorce)=>{console.dir('then resorce==>'+resorce);
});
复制代码

到这里,你应该看明白了吧,为了更专业性,下面我的写法会有所变化了...

3、Promise.prototype.finally(onFinally) 该方法补充了then和catch方法---执行catch,then之后都会执行的事件处理回调.避免在then和catch重复的代码.

let promise = new Promise(function(resove,reject){resove('have successed');
});
promise.then((data)=>{console.dir('then data==>'+data);
}
).catch((e)=>{console.dir('then resorce==>'+e);
}).finnaly(()=>{// all loadingconsole.dir('all loading');
});
复制代码

二、Promise之链式调用

看了上面的例子,好像Promise类似于Ajax的用法,又像一个代理. 没错Promise还真就做了这些事情.文章一开头说的,Promise为承诺而生.它承诺你在某个时候或某个状态执行给予反馈结果.

由于JavaScript的代码都是单线程的,导致所有网络操作,浏览器事件都必须是异步操作.通常的异步执行有三种,回调函数、事件监听以及发布订阅.我们这里只谈回调函数

1、先看个例子:

function foo(){console.log('1秒后执行');
}
let fn=setTimeout(function(){foo();
},1000);
//1秒后执行
复制代码

上面是个典型的回调函数的实现.

2、再来看下下面的例子:

function foo(){console.log('1秒后执行');
}
function fo(){console.log('1秒后执行');
}
setTimeout(function(){fo();setTimeout(function(){foo();
},1000);
},1000);
复制代码

如果有n个需求呢,是不是一直这么定义下去.看上去是不是很乱,不美观难以维护呢?

Promise首先最直观的的解决了,这个问题,让代码变得更为简洁,它采用链式的方式

3、对上面的例子做已调整,如下

function fo(){console.log('1秒后执行');
}
let promise =new Promise(function(resove,reject){setTimeout(function(){return resove(fo);},1000);
});
promise.then((data)=>{setTimeout(function(){return resove(data);},1000);
}).then((data)=>{console.log(data);
});
复制代码

以上代码是不是整洁了很多,有人会质疑promise不可能就这点能耐吧!

不着急,我们先来看下链式的原理,更进一步的了解下,然后再探讨其它的用法:

Promise 对象是一个代理对象(代理一个值),被代理的值在Promise对象创建时可能是未知的。它允许你为异步操作的成功和失败分别绑定相应的处理方法(handlers)。 这让异步方法可以像同步方法那样返回值,但并不是立即返回最终执行结果,而是一个能代表未来出现的结果的promise对象

一个 Promise有以下几种状态:

pending: 初始状态,既不是成功,也不是失败状态。
fulfilled: 意味着操作成功完成。
rejected: 意味着操作失败。
我们用视图来梳理下:
复制代码

pending 状态的 Promise 对象可能触发fulfilled 状态并传递一个值给相应的状态处理方法,也可能触发失败状态(rejected)并传递失败信息。当其中任一种情况出现时,Promise 对象的 then 方法绑定的处理方法(handlers )就会被调用(then方法包含两个参数:onfulfilled 和 onrejected,它们都是 Function 类型。当Promise状态为fulfilled时,调用 then 的 onfulfilled 方法,当Promise状态为rejected时,调用 then 的 onrejected 方法, 所以在异步操作的完成和绑定处理方法之间不存在竞争)。

因为 Promise.prototype.then 和 Promise.prototype.catch 方法返回promise 对象, 所以它们可以被链式调用。

出自 Promise.then() – JavaScript | MDN 通过上面介绍,相信对Promise的优点有了一定的了解了, 下面就常用的场景,再补充一下:

4、图片加载为例:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Promise</title><style>.pics{width: 300px;margin: 0 auto;}.pics img{display: block;width: 100%;}.loading{text-align: center;font-size: 14px;color: #111;}</style>
</head>
<body><div class="wrap"><div class="loading">正在加载...</div><div class="pics"></div></div><script></script>
</body>
</html>
复制代码
function loadImg (url) {return new Promise((resolve, reject) => {const img = new Image()img.onload = function () {resolve(img)}img.onerror = rejectimg.src = url})
}
复制代码
//递归调用
function syncLoad (index) {if (index >= urls.length) return Promise.resolve()return loadImg(urls[index]).then(img => {// addToHtml(img)return syncLoad (index + 1)})
}// 调用
syncLoad(0).then(() => {document.querySelector('.loading').style.display = 'none'
})
.catch(console.log)
复制代码

介绍完了链式处理Promise对象的实例之后,我们再来研究下.并发请求...

三、并发请求(Promise.all)

对于不需要按顺序加载,只需要按顺序来处理的并发请求,Promise.all 是最好的解决办法。因为Promise.all 是原生函数,我们就引用文档来解释一下。

Promise.all(iterable) 方法指当所有在可迭代参数中的 promises 已完成,或者第一个传递的 promise(指 reject)失败时,返回 promise。 出自 Promise.all() – JavaScript | MDN

const promises = urls.map(loadImg)
Promise.all(promises).then(imgs => {imgs.forEach(addToHtml)document.querySelector('.loading').style.display = 'none'}).catch(err => {console.error(err, 'Promise.all 当其中一个出现错误,就会reject。')})
复制代码

并发请求,按顺序处理结果

Promise.all 虽然能并发多个请求,但是一旦其中某一个 promise 出错,整个 promise 会被 reject.所以我们只要知道哪些图片出错了,把出错的图片再做一次请求或着用占位图补上就好.然后按顺序处理结果

方法一:

let task = Promise.resolve()
for (let i = 0; i < promises.length; i++) {task = task.then(() => promises[i]).then(addToHtml)
}
复制代码

方法二:

promises.reduce((task, imgPromise) => {return task.then(() => imgPromise).then(addToHtml)
}, Promise.resolve())
复制代码

四、并发请求(Promise.race)

Promise.race 接受一个 Promise 数组,返回这个数组中最先被 resolve 的 Promise 的返回值。
Promise.all接受一个 Promise 数组,返回这个数组中最后被 resolve 的 Promise 的返回值。
复制代码

通俗一点的理解:

all方法的效果实际上是【谁跑的慢,以谁为准执行回调】
race方法的效果实际上是【谁跑的快,以谁为准执行回调】
复制代码

因与all用法相似,这里就不做过多赘述了,下面我们来看下,ES7较ES6又增加了哪些支撑Promise的语法糖...

五、ES7支撑Promise的语法糖

老规矩,下看下实例:

function successCallback(result) {console.log("It succeeded with " + result);
}function failureCallback(error) {console.log("It failed with " + error);
}
doSomething(successCallback, failureCallback);
复制代码
async function foo() {try {let result = await doSomething();let newResult = await doSomethingElse(result);let finalResult = await doThirdThing(newResult);console.log(`Got the final result: ${finalResult}`);} catch(error) {failureCallback(error);}
}
复制代码

上面的例子,是否发现async、await这样的字眼,不见了then,catch了,对这就是在ECMAScript 2017标准的async/await语法糖中,这种同步形式代码的整齐性得到了极致的体现. 以上代码等价与

function foo() {
doSomething()
.then(result => doSomethingElse(value))
.then(newResult => doThirdThing(newResult))
.then(finalResult => console.log(`Got the final result: ${finalResult}`))
.catch(failureCallback);
}
复制代码

好处不言而喻

最后总结一下:

Promise是ES6的新特性,
简化异步请求层层回调的操作,
all和race实现并发请求,为很多业务场景提供了最佳的解决方案.
以及ES7新增的语法糖async,await大大简化了,Promise复杂的处理逻辑.
以上为个人一点点见解,如有错误或疑问,欢迎留言批评指正,如果没有设计到的请大家提供一下新的方式和方法。
复制代码

参考资料 JavaScript Promise:简介 | Web | Google Developers JavaScript Promise迷你书(中文版) JavaScript 之MDN web docs

JavaScript之Promise相关推荐

  1. JavaScript 的 Promise  和  C# 的 waitone 一样吗?请大家讨论i两句。

    JavaScript 的 Promise  和  C# 的 waitone 一样吗?请大家讨论i两句.

  2. 实现 JavaScript 异步方法 Promise.all

    本次的任务 假如..... JavaScript v8 引擎发生了重大故障,Promise.all 方法变成了 undefined ,为了拯救 JavaScript 世界,需要开发一个模块来解决此问题 ...

  3. 你真的了解JavaScript的Promise吗?

    什么是Promise Promise代理了一个可能要在未来才能到达的值[[PromiseValue]].Promise的一个最重要的特点是,你可以通过then来指定当[[PromiseValue]]到 ...

  4. JavaScript之Promise实现

    ES2015提出了Promise,同时基于Promise的异步开发将开发者中回调地狱中解救出来.但在没有原生支持的环境下,需要借助Promise/A+之类的库来实现Promise,今天就来尝试自行实现 ...

  5. javascript的promise

    'use strict'; // ajax函数将返回Promise对象: function ajax(method, url, data) {var request = new XMLHttpRequ ...

  6. Javascript ES6 Promise同步读取文件(使用async、await)

    const fs=require('fs'); const path=require('path');const dirname='D:\\HBuilderX\\Workspace\\NodeJS\\ ...

  7. Javascript ES6 Promise异步链式读取文件解决回调地狱

    const fs=require('fs'); const path=require('path');const dirname='D:\\HBuilderX\\Workspace\\NodeJS\\ ...

  8. JavaScript:Promise进阶知识

    Promise Promise就是ES6新增的一个用于解决异步编程的方案.以前,我们在处理异步的时候,都是在回调函数内做处理的.比如Ajax请求,是在success属性里面做异步处理的,那么如果在一个 ...

  9. 学习笔记 JavaScript ES6 Promise的静态方法

    学习内容: Promise.resolve() Promise.reject() Promise.all() Promise.race() Promise.resolve(),表示成功的状态 Prom ...

最新文章

  1. R语言pmax函数和pmin函数按位计算向量最大值、最小值实战
  2. mysql btmp 删除_mysql-如何在VDS上运行docker(lxd /容器)
  3. NoneBot2插件——打印系统状态
  4. 网格机房机柜、机架内的空间规划及理线方法
  5. easyUI创建人员树
  6. Android 开源框架Universal-Image-Loader学习
  7. Linux系统下MySQL的导出数据语句SELECT … INTO OUTFILE的用法
  8. linux编译ko文件(不同内核源码版本)
  9. 阐述简称PO,VO,TO,BO,DAO,POJO
  10. python打包成exe fail to ex_寻求帮助:pyinstaller打包.exe
  11. python实例化次数怎么算_关于python多次实例化
  12. 基于OleDb的Excel数据访问
  13. windows常用指令大全
  14. win7此计算机与未识别的网络连接,win7本地连接未识别的网络怎么办_win7本地连接未识别的网络怎么解决-win7之家...
  15. Python爬虫第四课 appium和第MongoDB数据库
  16. java imageio 保存_java-ImageIO保存回原始大小
  17. Java 16进制求和
  18. SpringBoot-HelloWorld
  19. gmssl国密sm2(生成密钥对-私钥签字-证书验签)
  20. java台球击球角度,台球瞄准方法--角度的计算----转

热门文章

  1. UVA 1593 Alignment of Code
  2. CentOS安装和配置Mysql
  3. 始于《将才》,而不止于将才
  4. R数据可视化--ggplot2定位之坐标系详解
  5. lamp介绍,wordpress,phpmyadmin,discuzz安装
  6. VMware View Composer 虚拟机映像管理
  7. 路由器与集线器、交换机的根本区别
  8. 74HC595的使用
  9. stm32对flash的读写保护与解除
  10. Keil宏定义和如何知道单片机资源名称