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. 想用Electron做个小工具?这个或许是终极版

    故事背景 之前在网上有看到很多小伙伴基于 electron 实现了非常多好用的桌面端工具,比如图床管理工具 PicGo,就专门做图床工具.也有一些其他的类似的小工具,比如 saladict-deskt ...

  2. 18 shell 重定向以及文件描述符

    1.对重定向的理解 2.硬件设备和文件描述符 文件描述符到底是什么 3.Linux Shell 输出重定向 4.Linux Shell 输入重定向 5.结合Linux文件描述符谈重定向 6.Shell ...

  3. Redis 高级面试题

    Redis 持久化机制 Redis 是一个支持持久化的内存数据库,通过持久化机制把内存中的数据同步到硬盘文件来 保证数据持久化.当 Redis 重启后通过把硬盘文件重新加载到内存,就能达到恢复数据的目 ...

  4. python之学生信息管理系统

    1 #!usr/bin/python 2 #encoding=utf-8 3 4 #1. 打印学生管理系统界面 5 def printStd(): 6 print ("*"*50) ...

  5. fast-poster海报生成器v1.4.0,一分钟完成海报开发

    fast-poster海报生成器v1.4.0,一分钟完成海报开发 介绍 一个快速开发动态海报的工具 在线体验:https://poster.prodapi.cn/ v1.4.0 新特性 为了项目和团队 ...

  6. 简单DOS命令

    1.nslookup命令 nslookup命令是用来解析域名的,举个例子:我们只知道百度的域名是www.baidu.com 想要知道它的ip的话就要使用nslookup命令了nslookup www. ...

  7. TOSCA自动化测试工具

    TOSCA由德国公司Tricentis研发,提供英文和德语两种版本. 目前他们的网上培训课程大约是2000一套,从初级到高级,从工程师到BA,有技术,也有测试管理. TOSCA的思想是,不用会编程的测 ...

  8. 00JAVA语法基础_四则运算 01

    自动生成30道四则运算的数学题,当前只是简单符合出题,答题和判断的代码,还没做要求,所以现在只是能随机生成三十道100以内的加减法和九九乘法表的乘除法 package Sizeyunsuan; /** ...

  9. Blazor 事件处理开发指南

    翻译自 Waqas Anwar 2021年3月25日的文章 <A Developer's Guide To Blazor Event Handling> [1] 如果您正在开发交互式 We ...

  10. Redis解读(4):Redis中HyperLongLog、布隆过滤器、限流、Geo、及Scan等进阶应用

    Redis中的HyperLogLog 一般我们评估一个网站的访问量,有几个主要的参数: pv,Page View,网页的浏览量 uv,User View,访问的用户 一般来说,pv 或者 uv 的统计 ...