php网站如何编辑,广东佛山企业,wordpress系统环境,一个做网站的软件文章目录 Promise 的介绍和优点#xff08;为什么需要 Promise#xff1f;#xff09;Promise 的基本使用Promise 的状态和回调函数Promise 对象的 3 种状态 Promise 的回调函数Promise的状态图#xff1a; new Promise() 是同步代码Promise 封装定时器Promise 封装 Ajax 请… 文章目录 Promise 的介绍和优点为什么需要 PromisePromise 的基本使用Promise 的状态和回调函数Promise 对象的 3 种状态 Promise 的回调函数Promise的状态图 new Promise() 是同步代码Promise 封装定时器Promise 封装 Ajax 请求resolve() 传入的参数重要 前言 Promise 是 JavaScript 中特有的语法。可以毫不夸张得说Promise 是ES6中最重要的语法没有之一。初学者可能对 Promise 的概念有些陌生但是不用担心。大多数情况下使用 Promise 的语法是比较固定的。我们可以先把这些固定语法和结构记下来多默写几遍然后在实战开发中逐渐去学习和领悟 Promise 的原理、底层逻辑以及细节知识点自然就慢慢掌握了。 在了解 Promise 之前必须要知道什么是回调函数这是必不可少的前置知识。关于回调函数的知识已经在上一篇文章中做了讲解。
Promise 的介绍和优点为什么需要 Promise
Promise 是异步编程的一种新的解决方案和规范。ES6将其写进了语言标准统一了用法原生提供了 Promise 对象。 Promise 对象, 可以用同步的表现形式来书写异步代码也就是说代码看起来是同步的但本质上的运行过程是异步的。使用 Promise 主要有以下优点 1、可以很好地解决ES5中的回调地狱的问题避免了层层嵌套的回调函数。 2、统一规范、语法简洁、可读性和和可维护性强。 3、Promise对象提供了简洁的 API使得管理异步任务更方便、更灵活。 从语法上讲Promise 是一个构造函数。从功能上来说Promise 对象用于封装一个异步操作并获取其成功/ 失败的结果值。
从写法规范上讲Promise 本质上是处理异步任务的一种编写规范要求每个人都按照这种规范来写。异步任务成功了该怎么写、异步任务失败了该怎么写、成功或者失败之后怎么通知调用者这些都有规定的写法。Promise 的目的就是要让每个使用ES6的人都遵守这种写法规范。
Promise 的伪代码结构大概是这样的 / 伪代码1 myPromise() .then( function () {}, function () {} ) .then( function () {}, function () {} ) .then( function () {}, function () {} ); // 伪代码2 是时候展现真正的厨艺了().然后(买菜).然后(做饭).然后(洗碗); 上面的伪代码可以看出业务逻辑上层层递进但是代码写法上却十分优雅没有过多的嵌套。
Promise 的基本使用
ES5中使用传统的回调函数处理异步任务时其基本模型的写法已在上一篇内容“回调函数”里讲过。
ES6中有了 Promise之后我们可以对那段代码进行改进基本模型不变。你会发现代码简洁规范了许多。
使用 Promise 处理异步任务的基本代码结构如下我们先来认识一下
// 使用 Promise 处理异步任务的基本模型// 封装异步任务
function requestData(url) {// resolve 和 reject 这两个单词是形参可以自由命名。大家的习惯写法是写成 resolve 和 rejectconst promise new Promise((resolve, reject) {const res {retCode: 0,data: qiangu yihaos data,errMsg: not login,};setTimeout(() {if (res.retCode 0) {// 网络请求成功resolve(res.data);} else {// 网络请求失败reject(res.errMsg);}}, 1000);});return promise;
}// 调用异步任务
requestData(www.qianguyihao.com/index1).then(data {console.log(异步任务执行成功:, data);
}).catch(err {console.log(异步任务执行失败:, err);
})// 再次调用异步任务
requestData(www.qianguyihao.com/index2).then(data {console.log(异步任务再次执行成功:, data);
}).catch(err {console.log(异步任务再次执行失败:, err);
})// 调用异步任务写法2
/* 这段代码的写法比较啰嗦。一般推荐上面的写法。
const myPromise requestData(www.qianguyihao.com/index1);
myPromise.then(data {console.log(异步任务执行成功:, data);
});
myPromise.catch(err {console.log(异步任务执行失败:, err);
});const myPromise2 requestData(www.qianguyihao.com/index2);
myPromise2.then(data {console.log(异步任务执行成功:, data);
});
myPromise2.catch(err {console.log(异步任务执行失败:, err);
});
*/在日常开发中使用Promise时80%以上的场景都符合上面的代码结构。你说它重不重要我们暂且先记下默写十遍形成肌肉记忆然后继续往下边学习边理解。
Promise 的状态和回调函数
Promise的三种状态是我们需要学习的第一个概念也是最重要的概念理解它才能理解 Promise的用法。
Promise 对象的 3 种状态
在使用 Promise 时我们可以将它划分为三种状态 pending等待中。属于初始状态既没有被兑现也没有被拒绝。 fulfilled已兑现/已解决/成功。执行了resolve() 时立即处于该状态表示 Promise已经被解决任务执行成功。 rejected已拒绝/失败。执行了 reject()时立即处于该状态表示 Promise已经被拒绝任务执行失败。 具体解释
1、Promise 的中文名翻译为“承诺”一般不称呼中文名。resolve 的中文翻译为“解决”reject 的中文翻译为“拒绝”。
2、当 new Promise()执行之后promise 对象的状态会被初始化为pending这个是初始状态。new Promise()这行代码括号里的内容是同步执行的。括号里可以再定义一 异步任务的 functionfunction 有两个参数resolve 和 reject。如下 如果异步任务成功了请执行 resolve()此时promise 的状态会自动变为 fulfilled。 如果异步任务失败了请执行 reject()此时promise 的状态会自动变为 rejected。 3、什么时候算成功什么时候算失败呢这是你自己定的需要结合具体需求和业务逻辑灵活决定。
关于 promise 的状态改变以及如何处理状态改变伪代码及详细注释如下
// 创建 promise 实例
const promise new Promise((resolve, reject) {//进来之后promise 的状态为 pendingconsole.log(同步代码); //这行代码是同步的//开始执行异步操作这里开始根据具体需求写异步的代码比如ajax请求 or 开启定时器if (异步的ajax请求成功) {console.log(233);// 如果请求成功了请写resolve()此时promise的状态会自动变为fulfilled成功状态resolve(请求成功并传参);} else {// 如果请求失败了请写reject()此时promise的状态会被自动变为rejected失败状态reject(请求失败并传参);}
});
console.log(qianguyihao);//调用promise的then()开始处理成功和失败
promise.then(successValue {// 处理 promise 的成功状态如果promise的状态为fulfilled则执行这里的代码console.log(successValue, 回调成功了); // 这里的 successMsg 是前面的 resolve(请求成功并传参) 传过来的参数},errorMsg {//处理 promise 的失败状态如果promise的状态为rejected则执行这里的代码console.log(errorMsg, 回调失败了); // 这里的 errorMsg 是前面的 reject(请求失败并传参) 传过来的参数}
);上面的注释要多看几遍。
Promise 的回调函数
Promise的回调函数伪代码如下
const promise new Promise(executor);// 【划重点】下面这两行代码是等价的选其中一种写法即可。这两种写法没有区别只是写法形式上的区别
promise.then(onFulfilled, onRejected);promise.then(onFulfilled).catch(onRejected);Promise是一个类通过 new Promise() 进行实例化构造出一个 Promise 实例对象。
1、Promise 的构造函数中需要传入一个参数这个参数是一个回调函数常用于处理异步任务。这个回调函数有一个专有名词叫 executor执行器因为在 new Promise() 时这个函数会立即执行。
可以在该回调函数中传入两个参数resolve 和 reject。我们可以在适当的时机执行 resolve()、reject()用于改变当前 Promise 实例的状态到成功或失败。
2当Promise状态变为成功时会触发 then() 方法里的回调函数的执行对成功的返回结果进行处理。
3当Promise状态变为失败时会触发 catch() 方法里的回调函数的执行对失败的返回结果进行处理。
2、then()方法的括号里面有两个参数分别代表两个回调函数 onFulfilled 和 onRejected这两个函数一直处于监听状态 参数1成功的回调函数。如果 Promise 的状态为 fulfilled意思是任务执行成功则触发 onFulfilled 函数的执行。 参数2失败的回调函数。如果 Promise 的状态为 rejected意思是任务执行失败则触发 onRejected 函数的执行。 3、**只有 Promise 的状态被改变之后才会走到 then() 或者 catch()。**也就是说在 new Promise() 时如果没有写 resolve()则 promise.then() 不执行如果没有写 reject()则 promise.catch() 不执行。
4、resolve()和 reject()这两个方法可以给 promise.then()、promise.catch()传递参数。
5、then() 可以被多次调用会按照顺序执行。比如
const promise new Promise(executor);// then() 可以被多次调用
promise.then(onFulfilled, onRejected);
promise.then(onFulfilled, onRejected);Promise的状态图 上面的Promise状态图很经典需要反复研读了然于胸。
Promise 的状态一旦改变就不能再变 Promise 的状态一旦改变就确定下来了不能再变。也不能再次执行 resolve()或者 reject()来改变状态。Promise 的状态改变是不可逆的。
代码举例
const p new Promise((resolve, reject) {resolve(1); // 代码执行到这里时 promise状态是 fulfilledresolve(111); // 这行重复代码写了没用等于没写reject(2); // 尝试修改状态为 rejected是不行的。因为状态执行到上面的 resolve(1)时已经被改变了。
});p.then((res) {console.log(res);
}).catch((err) {console.log(err);
});方代码的打印结果是 1而不是 2详见注释。
new Promise() 是同步代码
new Promise()这行代码本身是同步的。promise 如果没有使用 resolve 或 reject 更改状态时状态为 pending里面的代码是同步代码。
举例 1重要
// 会立即创建 Promise 实例
const promise1 new Promise((resolve, reject) {// 这行代码会立即执行console.log(qianguyihao1);
})console.log(promise1); // 此时 promise1 的状态为 pending准备阶段// 需要调用 promise2函数才会创建 Promise 实例
function promise2() {return new Promise((resolve, reject) {// 这行代码不会立即执行console.log(qianguyihao2);})
}上面的代码中我既没有写 reslove()也没有写 reject()。那么Promise 一直处于准备阶段。
此外需要特别注意的是promise1 中的 console.log() 会立即执行因为Promise的执行器函数在创建 Promise 实例时就会被调用并立即开始执行其中的代码逻辑。
举例 2
new Promise((resolve, reject) {console.log(promise1); // 这行代码是同步代码会立即执行
}).then((res) {console.log(promise then: res); // 这行代码不会执行因为前面没有写 resolve()所以走不到 .then
});打印结果
promise1上方代码仔细看注释如果前面没有写 resolve()那么后面的 .then是不会执行的。
举例 3
new Promise((resolve, reject) {resolve();console.log(promise1); // 代码1同步任务会立即执行
}).then(res {console.log(promise then); // 代码2异步任务中的微任务
});console.log(千古壹号); // 代码3同步任务打印结果
promise1
千古壹号
promise then代码解释
当完成异步任务之后状态分为成功或失败此时我们就可以用 reslove() 和 reject() 来修改 promise 的状态。
代码 1 是同步代码所以最先执行。代码 2 是微任务里面的代码所以要先等同步任务代码 3先执行完。当写完resolve();之后就会立刻把 .then()里面的代码加入到微任务队列当中。
补充知识异步任务分为“宏任务”、“微任务”两种。我们到后续的章节中再详细讲。
Promise 封装定时器
传统写法 写法 1
// 定义一个异步的延迟函数异步函数结束1秒之后再执行cb回调函数
function fun1(cb) {setTimeout(function () {console.log(即将执行cb回调函数);cb();}, 1000);
}// 先执行异步函数 fun1再执行回调函数 myCallback
fun1(myCallback);// 定义回调函数
function myCallback() {console.log(我是延迟执行的cb回调函数);
}写法 2精简版更常见
// 定义一个异步的延迟函数异步函数结束1秒之后再执行cb回调函数
function fun1(cb) {setTimeout(cb, 1000);
}// 先执行异步函数fun1再执行回调函数
fun1(function () {console.log(我是延迟执行的cb回调函数);
});上⾯的例⼦就是最传统的写法在异步结束后通过传入回调函数的方式执⾏函数。
学习 Promise 之后我们可以将这个异步函数封装为 Promise如下。
Promise 写法
function myPromise() {return new Promise((resolve) {setTimeout(resolve, 1000);});
}/* 【重要】上面的 myPromise 也可以写成
function myPromise() {return new Promise((resolve) {setTimeout(() {resolve();}, 1000);});
}
*/// 先执行异步函数 myPromise再执行回调函数
myPromise().then(() {console.log(我是延迟执行的回调函数);
});Promise 封装 Ajax 请求
传统写法
// 封装 ajax 请求传入回调函数 success 和 fail
function ajax(url, success, fail) {var xmlhttp new XMLHttpRequest();xmlhttp.open(GET, url);xmlhttp.send();xmlhttp.onreadystatechange function () {if (xmlhttp.readyState 4 xmlhttp.status 200) {success success(xmlhttp.responseText);} else {// 这里的 符号意思是如果传了 fail 参数就调用后面的 fail()如果没传 fail 参数就不调用后面的内容。因为 fail 参数不一定会传。fail fail(new Error(接口请求失败));}};
}// 执行 ajax 请求
ajax(/a.json,(res) {console.log(qianguyihao 第一个接口请求成功: JSON.stringify(res));},(err) {console.log(qianguyihao 请求失败: JSON.stringify(err));}
);上面的传统写法里定义和执行 ajax 时需要传⼊ success 和 fail 这两个回调函数进而执行回调函数。
注意看注释**callback callback()**这种格式的写法很常见。
Promise 写法 有了 Promise 之后我们不需要传入回调函数而是 先将 promise 实例化 然后在原来执行回调函数的地方改为执行对应的改变 promise 状态的函数 并通过 then … catch 或者 then …then 等写法实现链式调用提高代码可读性。 和传统写法相比promise 在写法上的大致区别是定义异步函数的时候将 callback 改为 resolve 和 reject待状态改变之后我们在外面控制具体执行哪些函数。
写法 1
// 封装 ajax 请求传入回调函数 success 和 fail
function ajax(url, success, fail) {var xmlhttp new XMLHttpRequest();xmlhttp.open(GET, url);xmlhttp.send();xmlhttp.onreadystatechange function () {if (xmlhttp.readyState 4 xmlhttp.status 200) {success success(xmlhttp.responseText);} else {// 这里的 符号意思是如果传了 fail 参数就调用后面的 fail()如果没传 fail 参数就不调用后面的内容。因为 fail 参数不一定会传。fail fail(new Error(接口请求失败));}};
}// 第一步model层的接口封装
function promiseA() {return new Promise((resolve, reject) {ajax(xxx_a.json, (res) {// 这里的 res 是接口的返回结果。返回码 retCode 是动态数据。if (res.retCode 0) {// 接口请求成功时调用resolve(request success res);} else {// 接口请求失败时调用reject({ retCode: -1, msg: network error });}});});
}// 第二步业务层的接口调用。这里的 data 就是 从 resolve 和 reject 传过来的也就是从接口拿到的数据
promiseA().then((res) {// 从 resolve 获取正常结果接口请求成功后打印接口的返回结果console.log(res);}).catch((err) {// 从 reject 获取异常结果console.log(err);});上方代码中当从接口返回的数据data.retCode的值接口返回码不同时可能会走 resolve也可能会走 reject这个由你自己的业务决定。
接口返回的数据一般是{ retCode: 0, msg: ‘qianguyihao’ } 这种 json 格式 retCode 为 0 代表请求接口成功所以前端对应会写if (res.retCode 0) 这样的逻辑。
另外上面的写法中是将 promise 实例定义成了一个函数 promiseA。我们也可以将 promise 实例定义成一个变量 promiseB达到的效果和上面的代码是一模一样的。写法如下写法上略有区别
写法 2
// 第一步model层的接口封装
const promiseB new Promise((resolve, reject) {ajax(xxx_a.json, (res) {// 这里的 res 是接口的返回结果。返回码 retCode 是动态数据。if (res.retCode 0) {// 接口请求成功时调用resolve(request success res);} else {// 接口请求失败时调用reject({ retCode: -1, msg: network error });}});
});// 第二步业务层的接口调用。这里的 data 就是 从 resolve 和 reject 传过来的也就是从接口拿到的数据
promiseB.then((res) {// 从 resolve 获取正常结果console.log(res);}).catch((err) {// 从 reject 获取异常结果console.log(err);});注意如果你用的是写法 1将 promise 实例定义为函数则调用 promise 的时候是promiseA().then()如果你用的是写法 2将 promise 实例定位为函数则调用的时候用的是promiseB.then()。写法 1 多了个括号不要搞混了。
resolve() 传入的参数重要
执行 resolve()之后Promise 的状态一定会变成 fulfilled 吗这是不一定的。
严格来说在我们调用 resolve 时如果 resolve()的参数中传入的值本身不是一个Promise那么会将该 promise 的状态变成 fulfilled。
resolve()的参数中可以传入哪些值Promise会进入哪种状态呢具体情况如下 情况1如果resolve()中传入普通的值或者普通对象包括 undefined那么Promise 的状态为fulfilled。这个值会作为then()回调的参数。这是最常见的情况。 情况2如果resolve()中传入的是另外一个新的 Promise那么原 Promise 的状态将交给新的 Promise 决定。 情况3如果resolve()中传入的是一个对象并且这个对象里有实现then()方法这种对象称为 thenable 对象那就会执行该then()方法并且根据then()方法的结果来决定Promise的状态。 情况3中我们通常称这个对象为 thenable 对象。thenable 的意思是在某个对象或者函数中定义了一个 then() 方法我们就称其为 thenable 对象/thenable函数。注意thenable对象里面的那个单词只能写 then不能写其他的单词如果写其他的单词就不是 thenable 对象了就不符合情况3而是符合情况1。
扩展一下reject()的参数中可以传入什么值呢无论传入什么值Promise 都会直接进入 rejected 状态并触发 catch() 方法的执行。
情况1的代码已经在前面反复出现过了接下来重点讲一下情况2 和情况3。
resolve() 中传入新的 Promise 代码举例
const promise1 new Promise((resolve, reject) {resolve(promise2);
});const promise2 new Promise((resolve, reject) {reject(promise2 的 reject);
});promise1.then(res {console.log(qianguyihao then);console.log(res);}).catch(err {console.log(qianguyihao catch);console.log(err);});打印结果
qianguyihao catch
promise2 的 reject代码解释
promise1 在执行resolve时传入的是 promise2。那么promise1接下来的状态将交给 promise2 处理。因为 promise2 执行的是 reject()所以 promise1 的状态进入 rejected执行 catch() 方法。
上方代码中如果把 promise1 和 promise2 的顺序换一下的话 代码会报错
const promise1 new Promise((resolve, reject) {resolve(promise2);
});const promise2 new Promise((resolve, reject) {reject(promise2 的 reject);
});promise1.then(res {console.log(qianguyihao then);}).catch(err {console.log(qianguyihao catch);console.log(err);});报错如下 resolve()中传入 thenable 对象 代码举例
const promise1 new Promise((resolve, reject) {// resolve 里传入了一个 thenable 对象里面有一个 then()方法then()方法里执行的是 reject()resolve({name: qianguyihao,then: (resolve, reject) {// 可以执行 resolve也可以执行 reject这里以 reject 为例reject(thenable reject);},});
});promise1.then(res {console.log(qianguyihao then);console.log(res);}).catch(err {console.log(qianguyihao catch);console.log(err);});打印结果
qianguyihao catch
thenable reject代码解释
promise1 在执行resolve时传入的是一个 thenable 对象。thenable 对象里有一个 then()方法。那么promise1接下来的状态将由 thenable 对象 里的 then() 方法决定。当前的代码中 then() 里执行的是 reject()所以 promise1 的状态进入 rejected执行 catch() 方法。
上方代码中如果把 thenable 对象里的单词then改成then1会怎么样呢那它就不是 thenable 对象只是一个普通的对象代码如下
const promise1 new Promise((resolve, reject) {// resolve 里传入了一个 thenable 对象里面有一个 then()方法then()方法里执行的是 reject()resolve({name: qianguyihao,// 把 单词 then 改成 then1就不符合 thenable 对象 的特征了then1: (resolve, reject) {reject(thenable resolve);},});
});promise1.then(res {console.log(qianguyihao then);console.log(JSON.stringify(res));}).catch(err {console.log(qianguyihao catch);console.log(err);});打印结果
qianguyihao then
{name:qianguyihao}