JavaScript之Promise
看完下面文章,你将了解到:
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相关推荐
- JavaScript 的 Promise 和 C# 的 waitone 一样吗?请大家讨论i两句。
JavaScript 的 Promise 和 C# 的 waitone 一样吗?请大家讨论i两句.
- 实现 JavaScript 异步方法 Promise.all
本次的任务 假如..... JavaScript v8 引擎发生了重大故障,Promise.all 方法变成了 undefined ,为了拯救 JavaScript 世界,需要开发一个模块来解决此问题 ...
- 你真的了解JavaScript的Promise吗?
什么是Promise Promise代理了一个可能要在未来才能到达的值[[PromiseValue]].Promise的一个最重要的特点是,你可以通过then来指定当[[PromiseValue]]到 ...
- JavaScript之Promise实现
ES2015提出了Promise,同时基于Promise的异步开发将开发者中回调地狱中解救出来.但在没有原生支持的环境下,需要借助Promise/A+之类的库来实现Promise,今天就来尝试自行实现 ...
- javascript的promise
'use strict'; // ajax函数将返回Promise对象: function ajax(method, url, data) {var request = new XMLHttpRequ ...
- Javascript ES6 Promise同步读取文件(使用async、await)
const fs=require('fs'); const path=require('path');const dirname='D:\\HBuilderX\\Workspace\\NodeJS\\ ...
- Javascript ES6 Promise异步链式读取文件解决回调地狱
const fs=require('fs'); const path=require('path');const dirname='D:\\HBuilderX\\Workspace\\NodeJS\\ ...
- JavaScript:Promise进阶知识
Promise Promise就是ES6新增的一个用于解决异步编程的方案.以前,我们在处理异步的时候,都是在回调函数内做处理的.比如Ajax请求,是在success属性里面做异步处理的,那么如果在一个 ...
- 学习笔记 JavaScript ES6 Promise的静态方法
学习内容: Promise.resolve() Promise.reject() Promise.all() Promise.race() Promise.resolve(),表示成功的状态 Prom ...
最新文章
- R语言pmax函数和pmin函数按位计算向量最大值、最小值实战
- mysql btmp 删除_mysql-如何在VDS上运行docker(lxd /容器)
- NoneBot2插件——打印系统状态
- 网格机房机柜、机架内的空间规划及理线方法
- easyUI创建人员树
- Android 开源框架Universal-Image-Loader学习
- Linux系统下MySQL的导出数据语句SELECT … INTO OUTFILE的用法
- linux编译ko文件(不同内核源码版本)
- 阐述简称PO,VO,TO,BO,DAO,POJO
- python打包成exe fail to ex_寻求帮助:pyinstaller打包.exe
- python实例化次数怎么算_关于python多次实例化
- 基于OleDb的Excel数据访问
- windows常用指令大全
- win7此计算机与未识别的网络连接,win7本地连接未识别的网络怎么办_win7本地连接未识别的网络怎么解决-win7之家...
- Python爬虫第四课 appium和第MongoDB数据库
- java imageio 保存_java-ImageIO保存回原始大小
- Java 16进制求和
- SpringBoot-HelloWorld
- gmssl国密sm2(生成密钥对-私钥签字-证书验签)
- java台球击球角度,台球瞄准方法--角度的计算----转