大家好,我是欧阳方超。
本次我们聚焦一下JavaScript中的Promise。
在引入Promise前,我们先假设这样一个场景,需要请求网络才能获得一些数据,然后将获得的数据渲染到页面当中,你可能已经想到这不就是基本的AJAX操作吗,没错,但是你是否还记得AJAX操作在处理正常结果和异常结果时代码写得是多么的繁琐,不够清爽,如下对成功和失败方法的调用都写进同一个函数了。
request.onreadystatechange = function () {
if (request.readyState === 4) {
if (request.status === 200) {
return success(request.responseText);
} else {
return fail(request.status);
}
}
}
而Promise就是一种的以更清爽的方式解决这类问题的技术,接着上面的假设场景,我们将“需要请求网络才能获得一些数据”的操作定义为生产者代码——产生数据的代码,将“然后将获得的数据渲染到页面当中”的操作定义为消费者代码——在生产者代码完成取数据的操作后立即使用其取得的数据,而Promise就是将生产者代码与消费者代码连接在一个的JavaScript对象,由此可以看出Promise有两个特点,其一是Promise是一个JavaScript对象,其二是它可以将生产者代码与消费者代码连接起来。
现在已经不负责任地引入了Promise的概念,再看一下它的语法:
let myPromise = new Promise(function (resolve, reject) {
//这里写生产这代码
});
创建Promise对象时需要给它的构造器传一个函数,该函数被称为executor,通过构造器创建Promise对象时传入的函数会被立即执行,该函数还有两个参数(resolve、reject),它们是JavaScript自身提供的回调,当executor无论何时执行完后它应该调用以下两个回调函数中的一个:
使用Promise构造器创建的Promise对象,具有以下内部属性:
state——promise对象的最初状态为pending,在resolve()函数被调用之后,状态变为fulfilled,在reject()函数被调用之后状态变为rejected;
result——promise对象的最初结果为undefined,在resolve(value)被调用后变为调用该函数时传入的值,在reject(err)被调用之后变成传入的err值;
state与result的变化详情可见下面三幅图:
promise状态的变化可以总结到下图中:
executor会在执行一项任务(一般会比较耗时)后调用resolve或reject来改变promise对应的状态。与promise的最初状态pending不同的是,一个fulfilled或rejected的promise都会被称为“settled”。
注意事项:
let promise = new Promise((resolve,reject)=>{
resolve();
});
一个Promise对象的作用是把executor与消费者连接起来,消费者端负责接收结果或错误。可以使用.then、.catch方法注册消费者端的函数。
then方法是最重要的方法,其语法如下:
promise.then(
function (result) {
//处理成功的结果
},
function (error) {
//处理错误的结果
}
);
上面then的第一个参数是一个函数,该函数会在promise的状态变为fulfilled且接收到结果后执行;
then的第二个参数也是函数,该函数会在promise的状态变为rejected之后执行。
下面是一个then的第一个参数被执行的情况:
let promise = new Promise((resolve,reject)=>{
resolve(123);
});
//then的第一个参数将被执行
promise.then(
(res) => {
console.log(res)
},
(error) => {
//不执行
}
)
下面是一个then的第二个参数被执行的情况:
let promise = new Promise((resolve,reject)=>{
reject(new Error("异常"));
});
//then的第二个参数将被执行
promise.then(
//不执行
(res) => {
console.log(res);
},
(error) => {
console.log(error);
}
)
其实小伙伴的代码都不是这样写的,大家都是只给then传一个参数,这样是可以的,如果只对成功的结果感兴趣,就可以只为then提供一个参数:
let promise = new Promise((resolve,reject)=>{
resolve("ok");
});
//为then只提供一个参数
promise.then(
(res) => {
console.log(res);
}
)
如果只对error感兴趣,其实可以对then的第一个参数传null,第二个参数传处理错误的函数:
let promise = new Promise((resolve,reject)=>{
reject(new Error("异常"));
});
//为then只提供一个参数
promise.then(null,
(err) => {
console.log(err);
}
)
上面处理错误时还有一种写法,那就是使用catch——据观察这也是小伙伴们用的多的方法,给catch只传一个处理错误的函数即可:
let promise = new Promise((resolve,reject)=>{
reject(new Error("异常"));
});
//为then只提供一个参数
promise.catch((err) => {
console.log(err);
}
)
finally是无论promise的状态如何都会执行的一个操作,这个似乎比较好理解。下面是使用它的注意事项:
let promise = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve("ok");
})
});
promise.finally(() => {
console.log("this is finally");
}).then((result) => {
console.log(result);
}
)
当promise的状态为pending时,.then、.catch、.finally都会等待其结果。我们可以为一个settled状态的promise添加处理程序,此时处理程序会立即执行。
在通过网络请求取得数据的场景中,生产者代码产生数据,消费者使用数据,而Promise就是将生产者代码与消费者代码连接在一个的JavaScript对象。
我是欧阳方超,把事情做好了自然就有兴趣了,如果你喜欢我的文章,欢迎点赞、转发、评论加关注。