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)
})
如果看了觉得有帮助的,我是@鹏多多11997110103,欢迎 点赞 关注 评论;
END
往期文章
- 超详细!Vuex手把手教程
- 使用nvm管理node.js版本以及更换npm淘宝镜像源
- 超详细!Vue-Router手把手教程
- vue中利用.env文件存储全局环境变量,以及配置vue启动和打包命令
- 微信小程序实现搜索关键词高亮
个人主页
网友评论