Promise教程及用法
1,介绍
Promise是异步编程的一种解决方案,比回调函数和事件更合理且更强大。可以理解为一个容器,里面保存着某个未来才会结束的事件的结果。
2,特点
Promise对象有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败),该状态不受外界影响。
状态可以从pending变为fulfilled,或者从pending变为rejected。一旦状态改变,就不会再变。
3,缺点
Promise一旦新建它就会立即执行,无法中途取消
如果不设置回调函数,Promise内部抛出的错误,不会反应到外部
当处于pending状态时,无法得知目前的进展是刚开始还是即将完成
4,基本用法
ES6
规定,Promise
对象是一个构造函数,用来生成Promise
实例,它接受一个函数作为参数,该函数的两个函数参数分别是resolve
和reject
,resolve
的作用是将Promise
对象的状态从未完成变为成功,reject
函数的作用是将Promise
对象的状态从未完成变为失败。
const promise = new Promise(function(resolve, reject) {
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
5,then
Promise实例生成以后,可以用then
方法分别指定resolved
状态和rejected
状态的回调函数(一般都只用第一个参数,reject
状态交由catch
专门处理)
function timeout(ms) {
return new Promise((resolve, reject) => {
setTimeout(resolve('done'), ms);
});
}
timeout(100).then(
// resolve回调
(value) => { console.log(value) },
// reject回调
(error) => { console.log(error) }
);
Promise
新建后就会立即执行,但是then
方法是微任务,将在当前脚本所有同步任务执行完才会执行。如下代码:首先输出的是A
。然后才是then
方法指定的回调函数,所以B
最后输出。
let promise = new Promise(function(resolve, reject) {
console.log('A');
resolve();
});
promise.then(function() {
console.log('B');
});
console.log('C');
// 输出顺序 A C B
then
方法返回的是一个新的Promise
实例(不是原来那个Promise
实例)。因此可以采用链式写法,即then
方法后面再调用另一个then
方法。
getJSON("/api")
.then(post => getJSON(post.commentURL))
.then(comments => console.log("resolve", comments))
如下代码:p2操作的结果是返回p1的异步操作结果。这时p1的状态就会传递给p2,也就是说,p1的状态决定了p2的状态。如果p1的状态是pending,那么p2的回调函数就会等待p1的状态改变;如果p1的状态已经是resolved或者rejected,那么p2的回调函数将会立刻执行。
const p1 = new Promise(function (resolve, reject) {
setTimeout(() => reject(new Error('fail')), 3000)
})
const p2 = new Promise(function (resolve, reject) {
setTimeout(() => resolve(p1), 1000)
})
p2
.then(result => console.log(result))
.catch(error => console.log(error))
6,catch
和then
一样,catch()
方法返回的也是一个Promise
对象,因此后面还可以接着调用then()
方法,如果没有报错,则会跳过catch()
方法。此时,要是后面的then()
方法里面报错,就与前面的catch()
无关了
const someAsyncThing = function() {
return new Promise(function(resolve, reject) {
// 下面一行会报错,因为x没有声明
resolve(x + 2);
});
};
someAsyncThing()
.catch(function(error) {
console.log('oh no', error);
})
.then(function() {
console.log('carry on');
});
7,finally
finally()方法是ES2018引入标准的。用于指定不管 Promise 对象最后状态如何,都会执行的操作。该方法总是会返回原来的值,并且不接受任何参数,这意味着没有办法知道前面的 Promise状态到底是fulfilled还是rejected。
promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});
8,all()
Promise.all()
方法用于将多个Promise
实例,包装成一个新的 Promise
实例。该方法接受一个数组作为参数(可以不是数组,但必须具有Iterator
接口,且返回的每个成员都是Promise
实例)
const p = Promise.all([p1, p2, p3]);
如上代码,p1
、p2
、p3
都是Promise
实例,如果不是,就会先调用Promise.resolve()
,将参数转为Promise
实例,再进一步处理。
注意:
只有数组里所有的
Promise
都完成,Promise.all()
才会完成如果数组里的
Promise
有一个失败,Promise.all()
就会失败,第一个失败的Promise
实例会传递给Promise.all()
的回调如果作为参数的
Promise
实例,自己定义了catch
方法,那么它一旦被rejected
,并不会触发Promise.all()
的catch
方法。
9,race()
Promise.race()
方法同样是将多个Promise
实例,包装成一个新的Promise
实例,参数与Promise.all()
方法一样。
const p = Promise.race([p1, p2, p3]);
race
的意思是速度,和字面意思一样,谁快,就取谁作为结果。上面代码中,只要p1
、p2
、p3
之中有一个实例率先改变状态,p
的状态就跟着改变。率先改变的Promise
实例的返回值,就传递给p
的回调函数。
10,allSettled()
Promise.allSettled()
方法接受一个数组作为参数,数组的每个成员都是一个Promise
对象,并返回一个新的Promise
数组集合。
注意:只有等到参数数组的所有Promise
对象都发生状态变更(不管是fulfilled
还是rejected
),返回的Promise
对象才会发生状态变更。
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('ok')
}, 1000)
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('no')
}, 2000)
})
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('ok')
}, 3000)
})
const all = Promise.allSettled([p1, p2, p3])
.then(res => {
console.log(res)
})
11,any()
Promise.any()
方法接受一个数组作为参数,数组的每个成员都是一个Promise
对象,并返回一个新的Promise
数组集合。
注意:只要参数数组的Promise
对象有一个变成fulfilled
状态,Promise.any()
就会变成fulfilled
状态。只有参数数组里所有Promise
对象都变成rejected
状态,Promise.any()
才会变成rejected
状态。
const all = Promise.any([p1, p2, p3])
.then(res => {
console.log(res)
})
.catch(err => {
console.log(err)
})
12,现有对象转为Promise对象
有时需要将现有对象转为Promise
对象,Promise.resolve()
和Promise.reject()
就起到这个作用。
onst p = Promise.resolve('Hello');
p.then(function (s) {
console.log(s)
});
// 输出 Hello
或者
Promise.reject('出错了')
.catch(e => {
console.log(e)
})
// 输出 出错了
13,实战用法
这里列举一些简单的例子,还有很多用处。
13.1,小程序request
const Request = (options) =>{
let url = baseURL + options.url;
return new Promise((resolve, reject) => {
wx.request({
url,
data: options.data || {},
method: options.method || 'post',
responseType: options.responseType || '',
timeout: 15000,
success (res) {
if(res.statusCode === 200){
resolve(res.data);
}else{
FN.Toast(res.errMsg);
};
},
fail (res) {
FN.Toast("网络开小差了");
reject(res);
}
})
})
}
13.2,图片加载
const preloadImage = function (path) {
return new Promise(function (resolve, reject) {
const image = new Image();
image.onload = resolve;
image.onerror = reject;
image.src = path;
});
}
13.3,封装Toast
import { Message, MessageBox} from 'element-ui'
/**
* 提示框
* @param {String} text
*/
alert(text) {
return new Promise((resolve, reject) => {
MessageBox.alert(text, '温馨提示', {
confirmButtonText: '确定',
callback: action => {
if (action === 'confirm'){
resolve(action)
} else {
reject(action)
}
}
})
})
}
14,手写Promise
class myPromise {
constructor(executor) {
this.initState()
this.initBind()
try {
executor(this.resolve, this.reject)
} catch (error) {
this.reject(error)
}
}
initState() {
this.result = null
this.state = 'pending'
this.resolveCallback = []
this.rejectCallback = []
}
initBind() {
this.resolve = this.resolve.bind(this)
this.reject = this.reject.bind(this)
}
resolve(value) {
if (this.state !== 'pending') return
this.result = value
this.state = 'success'
while (this.resolveCallback.length) {
this.resolveCallback.shift()(this.result)
}
}
reject(value) {
if (this.state !== 'pending') return
this.result = value
this.state = 'error'
while (this.rejectCallback.length) {
this.rejectCallback.shift()(this.result)
}
}
then(onResolve, onReject) {
onResolve = typeof onResolve === 'function' ? onResolve : res => res
onReject = typeof onReject === 'function' ? onReject : res => res
switch (this.state) {
case 'pending':
this.resolveCallback.push(onResolve.bind(this))
this.rejectCallback.push(onReject.bind(this))
break
case 'success':
onResolve(this.result)
break
case 'error':
onReject(this.result)
break
}
}
catch(onReject) {
return this.then(null, onReject)
}
}
const fn = new myPromise((resolve, reject) => {
setTimeout((res) => {
resolve('成功')
}, 2000)
})
.then(res => {
console.log(res)
})
如果看了觉得有帮助的,我是@鹏多多,欢迎 点赞 关注 评论;END
公众号
往期文章
- 使用nvm管理node.js版本以及更换npm淘宝镜像源
- 超详细!Vue-Router手把手教程
- vue中利用.env文件存储全局环境变量,以及配置vue启动和打包命令
- 微信小程序实现搜索关键词高亮
- 超详细!Vue的九种通信方式
- 超详细!Vuex手把手教程
个人主页
Promise教程及用法的更多相关文章
- Promise的简单用法
众所周知的,Javascript是一种单线程的语言,所有的代码必须按照所谓的“自上而下”的顺序来执行.本特性带来的问题就是,一些将来的.未知的操作,必须异步实现.本文将讨论一个比较常见的异步解决方案— ...
- 深入浅出:promise的各种用法
https://mp.weixin.qq.com/s?__biz=MzAwNTAzMjcxNg==&mid=2651425195&idx=1&sn=eed6bea35323c7 ...
- ES6之Promise的基本用法
之前多次看过阮一峰的ES6教程,对Promise也简单的理解过,但是,由于没在项目中运用过,所以记忆的并不深刻,昨天在进行项目的改良,有一个地方需要用到Promise 所以就这样写了: onload函 ...
- 关于promise的一些用法
Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果.从语法上说,Promise 是一个对象,从它可以获取异步操作的消息. Promise对象有以下两个特点 ...
- Promise 的基础用法
Promise 的含义 Promise 是异步编程的一种解决方案,比传统的解决方案–回调函数和事件--更合理和更强大.它由社区最早提出和实现,ES6将其写进了语言标准,统一了语法,原生提供了Promi ...
- vue+axios+promise实际开发用法
axios它是基于promise的http库,可运行在浏览器端和node.js中,然后作者尤雨溪也是果断放弃了对其官方库vue-resource的维护,直接推荐axios库,小编我也是从vue-res ...
- promise请求数据用法
Promise简介 Promise 是异步编程的一种解决方案,比传统的解决方案–回调函数和事件--更合理和更强大.ES6将其写进了语言标准,统一了语法,里面保存着某个未来才回结束的事件(通常是一个异步 ...
- promise 的基本用法
//知识点1 例1--- 最基本的写法 Promise的基本语法哦 const Aa=new Promise(function(resolve,reject){ //resolve和reject是参数 ...
- [转]史上最最最详细的手写Promise教程
我们工作中免不了运用promise用来解决异步回调问题.平时用的很多库或者插件都运用了promise 例如axios.fetch等等.但是你知道promise是咋写出来的呢? 别怕-这里有本promi ...
随机推荐
- Java运算中的类型转换
类型转换 运算中,不同类型的数据先转化为同一类型,然后进行运算 public class Dome04 { public static void main(String[] args) { //int ...
- JAVA 中的权限访问修饰符(public,protected,default,private )
JAVA中有四个权限访问修饰符:public,protected,default,private 注意:这里讲的是对类中属性和方法的访问权限,并不是类的访问权限 1.default:包访问权限 如果什 ...
- CentOS-配置jar包自启动(SpringBoot)
在pom.xml文件<plugin>中添加配置后,再打包(开发人员) <plugin> <groupId>org.springframework.boot& ...
- Linux之 du的用法
du 显示目录和文件的大小,常用命令为 du -sh * du -sm * | sort -n //统计当前目录大小 并按大小 排序 du 无参数 显示当前路径下的目录大小和子目录大小 -b/-k/- ...
- MYSQL数据库数据拆分之分库分表总结 (转)
数据存储演进思路一:单库单表 单库单表是最常见的数据库设计,例如,有一张用户(user)表放在数据库db中,所有的用户都可以在db库中的user表中查到. 数据存储演进思路二:单库多表 随着用户数 ...
- centos7 之 设置环境变量(转载)
设置centos环境变量,可以用export命令,也可以通过修改文件形式实现,本文以lavavel需要设置环境变量为例,将 /root/.config/composer/vendor/bin 路径加到 ...
- ARTS第十周
之前忘了发布 1.Algorithm:每周至少做一个 leetcode 的算法题2.Review:阅读并点评至少一篇英文技术文章3.Tip:学习至少一个技术技巧4.Share:分享一篇有观点和思考的 ...
- Node性能如何进行监控以及优化?
一. 是什么 Node作为一门服务端语言,性能方面尤为重要,其衡量指标一般有如下: CPU 内存 I/O 网络 CPU 主要分成了两部分: CPU负载:在某个时间段内,占用以及等待CPU的进程总数 C ...
- 高校表白App-团队冲刺第五天
今天要做什么 封装Adapter制作引导页 今天做了什么 成功封装工具类,为以后的轮播做了铺垫 遇到的问题 在封装时采用数组容器进行操作,只能添加图片作为元素,对于layout不可加入
- Java基础00-Stream流34
1. Stream流 Stream流 1.1 体验Stream流 代码示例: //需求:按照下面的要求完成集合的创建和遍历 public class StreamDemo { public stati ...