1,介绍

Promise是异步编程的一种解决方案,比回调函数和事件更合理且更强大。可以理解为一个容器,里面保存着某个未来才会结束的事件的结果。

2,特点

  • Promise对象有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败),该状态不受外界影响。

  • 状态可以从pending变为fulfilled,或者从pending变为rejected。一旦状态改变,就不会再变。

3,缺点

  • Promise一旦新建它就会立即执行,无法中途取消

  • 如果不设置回调函数,Promise内部抛出的错误,不会反应到外部

  • 当处于pending状态时,无法得知目前的进展是刚开始还是即将完成

4,基本用法

ES6规定,Promise对象是一个构造函数,用来生成Promise实例,它接受一个函数作为参数,该函数的两个函数参数分别是resolverejectresolve的作用是将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]);

如上代码,p1p2p3都是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的意思是速度,和字面意思一样,谁快,就取谁作为结果。上面代码中,只要p1p2p3之中有一个实例率先改变状态,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

公众号

往期文章

个人主页

Promise教程及用法的更多相关文章

  1. Promise的简单用法

    众所周知的,Javascript是一种单线程的语言,所有的代码必须按照所谓的“自上而下”的顺序来执行.本特性带来的问题就是,一些将来的.未知的操作,必须异步实现.本文将讨论一个比较常见的异步解决方案— ...

  2. 深入浅出:promise的各种用法

    https://mp.weixin.qq.com/s?__biz=MzAwNTAzMjcxNg==&mid=2651425195&idx=1&sn=eed6bea35323c7 ...

  3. ES6之Promise的基本用法

    之前多次看过阮一峰的ES6教程,对Promise也简单的理解过,但是,由于没在项目中运用过,所以记忆的并不深刻,昨天在进行项目的改良,有一个地方需要用到Promise 所以就这样写了: onload函 ...

  4. 关于promise的一些用法

    Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果.从语法上说,Promise 是一个对象,从它可以获取异步操作的消息. Promise对象有以下两个特点 ...

  5. Promise 的基础用法

    Promise 的含义 Promise 是异步编程的一种解决方案,比传统的解决方案–回调函数和事件--更合理和更强大.它由社区最早提出和实现,ES6将其写进了语言标准,统一了语法,原生提供了Promi ...

  6. vue+axios+promise实际开发用法

    axios它是基于promise的http库,可运行在浏览器端和node.js中,然后作者尤雨溪也是果断放弃了对其官方库vue-resource的维护,直接推荐axios库,小编我也是从vue-res ...

  7. promise请求数据用法

    Promise简介 Promise 是异步编程的一种解决方案,比传统的解决方案–回调函数和事件--更合理和更强大.ES6将其写进了语言标准,统一了语法,里面保存着某个未来才回结束的事件(通常是一个异步 ...

  8. promise 的基本用法

    //知识点1 例1--- 最基本的写法 Promise的基本语法哦 const Aa=new Promise(function(resolve,reject){ //resolve和reject是参数 ...

  9. [转]史上最最最详细的手写Promise教程

    我们工作中免不了运用promise用来解决异步回调问题.平时用的很多库或者插件都运用了promise 例如axios.fetch等等.但是你知道promise是咋写出来的呢? 别怕-这里有本promi ...

随机推荐

  1. Java运算中的类型转换

    类型转换 运算中,不同类型的数据先转化为同一类型,然后进行运算 public class Dome04 { public static void main(String[] args) { //int ...

  2. JAVA 中的权限访问修饰符(public,protected,default,private )

    JAVA中有四个权限访问修饰符:public,protected,default,private 注意:这里讲的是对类中属性和方法的访问权限,并不是类的访问权限 1.default:包访问权限 如果什 ...

  3. CentOS-配置jar包自启动(SpringBoot)

    在pom.xml文件<plugin>中添加配置后,再打包(开发人员) <plugin>     <groupId>org.springframework.boot& ...

  4. Linux之 du的用法

    du 显示目录和文件的大小,常用命令为 du -sh * du -sm * | sort -n //统计当前目录大小 并按大小 排序 du 无参数 显示当前路径下的目录大小和子目录大小 -b/-k/- ...

  5. MYSQL数据库数据拆分之分库分表总结 (转)

      数据存储演进思路一:单库单表 单库单表是最常见的数据库设计,例如,有一张用户(user)表放在数据库db中,所有的用户都可以在db库中的user表中查到. 数据存储演进思路二:单库多表 随着用户数 ...

  6. centos7 之 设置环境变量(转载)

    设置centos环境变量,可以用export命令,也可以通过修改文件形式实现,本文以lavavel需要设置环境变量为例,将 /root/.config/composer/vendor/bin 路径加到 ...

  7. ARTS第十周

     之前忘了发布 1.Algorithm:每周至少做一个 leetcode 的算法题2.Review:阅读并点评至少一篇英文技术文章3.Tip:学习至少一个技术技巧4.Share:分享一篇有观点和思考的 ...

  8. Node性能如何进行监控以及优化?

    一. 是什么 Node作为一门服务端语言,性能方面尤为重要,其衡量指标一般有如下: CPU 内存 I/O 网络 CPU 主要分成了两部分: CPU负载:在某个时间段内,占用以及等待CPU的进程总数 C ...

  9. 高校表白App-团队冲刺第五天

    今天要做什么 封装Adapter制作引导页 今天做了什么 成功封装工具类,为以后的轮播做了铺垫 遇到的问题 在封装时采用数组容器进行操作,只能添加图片作为元素,对于layout不可加入

  10. Java基础00-Stream流34

    1. Stream流 Stream流 1.1 体验Stream流 代码示例: //需求:按照下面的要求完成集合的创建和遍历 public class StreamDemo { public stati ...