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. layui table 使用table放输入框时控制每列的宽度

    <table class="layui-table" lay-filter="demo"> <colgroup> <%--设置每列 ...

  2. python之字典(dict)基础篇

    字典:dict 特点: 1>,可变容器模型,且可存储任意类型对象,字符串,列表,元组,集合均可: 2>,以key-value形式存在,每个键值 用冒号 : 分割,每个键值对之间用逗号 , ...

  3. java封装继承以及多态(含代码)

    封装 该露的露,该藏的藏 我们常需设计要追求,"高内聚,低耦合".高内聚就是类的内部数据操作细节自己完成.不允许外部干涉:低耦合:仅暴漏少量的方法给外部使用. 封装(数据的隐藏) ...

  4. runtime使用总结

    runtime这个东西,项目是很少用到的,但面试又避不可少,了解其内部的机制对底层的理解还是很有必要的. 1.动态添加属性 拓展类别属性的简单实现 a.定义字面量指针 static char dyna ...

  5. 浅谈C++11中的多线程(二)

    摘要 本篇文章围绕以下几个问题展开: 进程和线程的区别 何为并发?C++中如何解决并发问题?C++中多线程的基本操作 浅谈C++11中的多线程(一) - 唯有自己强大 - 博客园 (cnblogs.c ...

  6. IP数据包格式与ARP转发原理

    一.网络层简介1.网络层功能2.网络层协议字段二.ICMP与封装三.ARP协议与ARP欺骗1.ARP协议2.ARP欺骗 1.网络层功能 1. 定义了基于IP地址的逻辑地址2. 连接不同的媒介3. 选择 ...

  7. ELK多索引配置(filebeat)

     nginx日志收集: ​ ​ #-------------------------输入 filebeat.inputs: ​ #----------json日志---------- ​ - type ...

  8. java集合(2)-Collection与Iterator接口

    1 package com.j1803.collectionOfIterator; 2 import java.util.ArrayList; 3 import java.util.Collectio ...

  9. 在R中使用Keras和TensorFlow构建深度学习模型

    一.以TensorFlow为后端的Keras框架安装 #首先在ubuntu16.04中运行以下代码 sudo apt-get install libcurl4-openssl-dev libssl-d ...

  10. 通过http将yum仓库发布

    说明:这里是Linux服务综合搭建文章的一部分,本文可以作为单独构建http和发布yum仓库到内网的参考. 注意:这里所有的标题都是根据主要的文章(Linux基础服务搭建综合)的顺序来做的. 如果需要 ...