js Promise
异步编程
JS异步机制
- 回调函数
使用多个回调函数嵌套会造成回调地狱,上下两层的代码耦合度高。 - Promise
Promise是ES6引入的异步编程的解决方案,Promise可以封装异步操作,获取成功和失败的结果。Promise的优点是:支持链式调用,可以解决回调地狱问题。 - generator
- async
当函数内部执行到一个await语句时,如果语句返回一个promise对象,那么函数会等待promise变为resolve状态在继续向下执行。
setTimeout、Promise、Async/Await 的区别
- setTimeout
console.log('script start') //1. 打印 script start
setTimeout(function(){
console.log('settimeout') // 4. 打印 settimeout
}) // 2. 调用 setTimeout 函数,并定义其完成后执行的回调函数
console.log('script end') //3. 打印 script start
// 输出顺序:script start->script end->settimeout
- Promise
Promise本身是同步的立即执行函数,当在执行器中执行resolve或者reject的时候,此时是异步操作,会先执行then/catch等,当主栈完成后,才会去调用resolve/reject中存放的方法执行。
console.log('script start')
let promise1 = new Promise(function (resolve) {
console.log('promise1')
resolve()
console.log('promise1 end')
}).then(function () {
console.log('promise2')
})
setTimeout(function(){
console.log('settimeout')
})
console.log('script end')
// 输出顺序: script start->promise1->promise1 end->script end->promise2->settimeout
当JS主线程执行到Promise对象时:
- promise1.then() 的回调就是一个 task
- promise1 是 resolved或rejected: 那这个 task 就会放入当前事件循环回合的 microtask queue
- promise1 是 pending: 这个 task 就会放入 事件循环的未来的某个(可能下一个)回合的 microtask queue 中
- setTimeout 的回调也是个 task ,它会被放入 macrotask queue 即使是 0ms 的情况
- async/await
async 函数返回一个 Promise 对象,当函数执行的时候,一旦遇到 await 就会先返回,等到触发的异步操作完成,再执行函数体内后面的语句。可以理解为,是让出了线程,跳出了 async 函数体。
对Promise的理解
Promise是一种异步编程的解决方案,可以解决回调地狱问题。Promise有三种状态:pending(进行中)、resolved(已完成)、rejected(已拒绝)。Promise只能由pending转化到resolved状态或pending转化到rejected状态。一旦从进行中状态转化为其他状态就不可再改变了。
Promise使用流程
首先创建Promise实例,然后Promise对象会执行异步操作,若异步操作成功,则调用resolve()方法并将Promise对象的状态改为resolved,失败则调用reject()方法并将Promise对象的状态改为rejected。在后续调用then方法时,若Promise对象的的状态为resolved,则调用第一个回调函数,否则调用第二个回调函数。then()方法的返回对象也是一个Promise对象,因此可以进行链式调用。
Promise转换状态的三种方式
- resolve函数
- reject函数
- 抛出错误:使用throw抛出错误,promise的状态变为rejected
Promise的缺点:
- 无法取消,一旦新建就会立即执行。
- 如果不设置回调函数,Promise内部抛出错误,不会反应到外部。
Promise是改变状态先执行还是指定回调先执行
当执行器中的代码为同步时,会先改变状态后执行回调。
let promise1 = new Promise((resolve, reject) => {
resolve("ok1")
console.log(111);
}).then(res => {
console.log(res);
}).catch(err => {
console.log(err);
})
当执行器中的代码为异步时,会先执行回调再改变状态。
let promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("ok2")
}, 100)
}).then(res => {
console.log(222);
console.log(res);
}).catch(err => {
console.log(err);
})
Promise.then()返回新的promise的结果状态由什么决定?
由then()返回的回调函数执行的结果决定。
- 如果抛出异常,则新的promise的状态为rejected
- 如果返回的是非promise的值,则新的promise状态为fulfilled
- 如果返回的是promise,则promise的执行结果为新的promise的结果
如何中断promise链
返回一个状态为pendding的promise对象。
Promise的基本用法
- 创建Promise对象。
Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve、reject。
const promise1 = new Promise((resolve, reject) => {
...
resolve('promise1')
...
}).then(res => { // then方法接受两个回调函数作为参数,第一个回调函数在请求成功时调用,第二个在失败时调用。
...
},()=>{
}).catch(err=>{
console.log(err)
})
- Promise方法
all()
all()方法可以完成并行任务,它接收一个数组,数组的每一项都是一个promise对象,当数组中所有的promise的状态都达到了resolved的时候,all方法的状态就会变为resolved,如果有一个状态变为了rejected,那么all方法的状态就会变成rejected。all()方法成功后返回一个数组,该数组记录着每个promise的resolve执行的值。失败后返回最先被reject失败状态的值。
race()
race()方法和all()方法一样,区别是race()会返回最先执行完的promise对象。
race()方法可以用来解决某一件事超过多久就不做了。例如:
Promise.race(promise1, timeOutPromise(5000)).then(res=>{})
finally()
finally()方法用于指定不管Promise对象最后状态如何,都会执行的操作。
async
async的返回值为promise对象。这个promise的状态是由async的返回值决定的。
await
await必须写在async()函数内部,await表达式的运算结果取决于它等的是什么:
- 如果它等到是普通表达式,那么表达式的运算结果就是await返回的结果。
- 如果等到的是promise对象,那么await会等promise对象的状态变为resolve后,得到resolve的值,作为await表达式的运算结果。
async/await对比promise的优势
- 代码阅读起来更加像同步。promise虽然解决了回调地狱问题,但then的链式调用也会带来额外的阅读负担。
- 调试友好。调试器只能跟踪同步代码的每一步。
- 错误处理友好。
- promise传递中间值比较麻烦,而async/await几乎是同步写法,非常优雅。
promise、async&await和setTimeout运行顺序
- JS运行的机制
JS有一个主线程和一个调用栈,所有的任务都会被放到调用栈中等待主线程执行。
在JS中,任务被分为两种,一种宏任务,一种微任务。
宏任务主要为script全部代码、setTimeout、setInterval。
微任务执行栈在执行完同步任务后,查看执行栈是否为空,如果执行栈为空,就会去检查微任务队列是否为空,如果为空时,就执行宏任务,否则就一次性执行完所有微任务。
- setTimeout属于宏任务;Promise本身属于同步的立即执行函数,Promise.then()属于微任务;async方法执行时,遇到await会立即执行await后面的代码,在await之后的代码放入微任务队列。
JS运行的流程为:
- 首先执行同步代码
- 若遇到宏任务调用则同步执行宏任务代码
- 宏任务代码执行完后,检测微任务队列,若微任务队列不为空,一次性执行完所有微任务
- 重复2.3步骤直到所有代码执行完毕
并行和并发的区别
并发 | 并行 | |
---|---|---|
概念 | 在某个时刻通过CPU切换对多个任务进行处理 | 同一时刻发生多个事件 |
CPU资源 | 需要对CPU资源进行抢占 | 不会对CPU资源进行抢占 |
线程切换 | 会进行线程切换 | 线程之间不会进行切换 |
setTimeout、setInterval、requestAnimationFrame 各有什么特点?
setTimeout
由于JS是单线程执行的,如果前面的代码影响了性能,就会导致setTimeout不会按期执行。可以通过代码修正校准定时器。
setInterval
setInterval是每隔一定delay就执行一次回调函数。它和setTimeout一样,不能在预期的时间执行任务,而且存在累计执行的问题。
setInterval的缺点:
- 无视代码错误:setInterval不关心自己调用的代码是否报错
- 无网络延迟:setInterval不会管网络延迟(流量剧增、临时断网、带宽限制等),指挥定时发送请求,导致客户端网络队列中都是请求。
- 不保证执行:如果你调用的函数需要花很长时间才能完成,那某些调用会被直接忽略。
setTimeout和setInterval的区别
setTimeout() 方法用于在指定的毫秒数后调用函数或计算表达式;而setInterval()则可以在每隔指定的毫秒数循环调用函数或表达式,直到clearInterval把它清除。
setTimeout()只执行一次,setInterval()可以执行多次。
setTimeout用于延迟执行某方法或功能。setInterval则一般用于刷新表单,对于一些表单的假实时指定时间刷新同步。
requestAnimationFrame
requestAnimationFrame自带函数节流功能,延时效果精准。
手撕promise
1. 初始结构搭建
function Promise(executor) {
}
// 给Promise的原型上添加then方法
Promise.prototype.then = function (onResolved, onRejected) {
}
2. resolve和reject结构搭建
function Promise(executor) {
function resolve(data) {
}
function reject(data) {
}
// 执行器函数是同步调用的
executor(resolve, reject)
}
// 给Promise的原型上添加then方法
Promise.prototype.then = function (onResolved, onRejected) {
}
3. resolve和reject代码实现
function Promise(executor) {
this.PromiseState = "pending"
this.PromiseResult = null
// 这里的this指向Promise对象
// console.log(this);
// 因为在resolve里面,this指向的是window不是Promise对象,所以应该预先保存实例对象的this值
const self = this
function resolve(data) {
// 这里的this指向window
// console.log(this); // 指向window
// console.log(self); // 指向promise对象
self.PromiseState = "fulfilled"
self.PromiseResult = data
}
function reject(err) {
self.PromiseState = "rejected"
self.PromiseResult = err
}
// 执行器函数是同步调用的
executor(resolve, reject)
}
// 给Promise的原型上添加then方法
Promise.prototype.then = function (onResolved, onRejected) {
}
这里需要注意的是,在resolve()函数中 要改变PromiseState和PromiseResult的值需要 更改this指向。因为在resolve()函数中this指向window
,而Promise函数内this指向Promise对象
,所以要在Promise函数中将this指向保存下来,再进行更改。
4. 抛出异常改变状态
function Promise(executor) {
this.PromiseState = "pending"
this.PromiseResult = null
// 这里的this指向Promise对象
// console.log(this);
// 因为在resolve里面,this指向的是window不是Promise对象,所以应该预先保存实例对象的this值
const self = this
function resolve(data) {
// 这里的this指向window
// console.log(this); // 指向window
// console.log(self); // 指向promise对象
self.PromiseState = "fulfilled"
self.PromiseResult = data
}
function reject(err) {
self.PromiseState = "rejected"
self.PromiseResult = err
}
// 捕获异常
try {
// 执行器函数是同步调用的
executor(resolve, reject)
} catch (error) {
// 调用reject函数修改Promise对象的状态和值
reject(error)
}
}
// 给Promise的原型上添加then方法
Promise.prototype.then = function (onResolved, onRejected) {
}
5. Promise的状态只能修改一次
function Promise(executor) {
this.PromiseState = "pending"
this.PromiseResult = null
// 这里的this指向Promise对象
// console.log(this);
// 因为在resolve里面,this指向的是window不是Promise对象,所以应该预先保存实例对象的this值
const self = this
function resolve(data) {
if (self.PromiseState !== "pending") return
// 这里的this指向window
// console.log(this); // 指向window
// console.log(self); // 指向promise对象
self.PromiseState = "fulfilled"
self.PromiseResult = data
}
function reject(err) {
if (self.PromiseState !== "pending") return
self.PromiseState = "rejected"
self.PromiseResult = err
}
// 捕获异常
try {
// 执行器函数是同步调用的
executor(resolve, reject)
} catch (error) {
// 调用reject函数修改Promise对象的状态和值
reject(error)
}
}
// 给Promise的原型上添加then方法
Promise.prototype.then = function (onResolved, onRejected) {
}
6. then方法执行回调
function Promise(executor) {
this.PromiseState = "pending"
this.PromiseResult = null
// 这里的this指向Promise对象
// console.log(this);
// 因为在resolve里面,this指向的是window不是Promise对象,所以应该预先保存实例对象的this值
const self = this
function resolve(data) {
if (self.PromiseState !== "pending") return
// 这里的this指向window
// console.log(this); // 指向window
// console.log(self); // 指向promise对象
self.PromiseState = "fulfilled"
self.PromiseResult = data
}
function reject(err) {
if (self.PromiseState !== "pending") return
self.PromiseState = "rejected"
self.PromiseResult = err
}
// 捕获异常
try {
// 执行器函数是同步调用的
executor(resolve, reject)
} catch (error) {
// 调用reject函数修改Promise对象的状态和值
reject(error)
}
}
// 给Promise的原型上添加then方法
Promise.prototype.then = function (onResolved, onRejected) {
// 这里的this指向Promise对象
// console.log(this);
// 调用回调函数
if (this.PromiseState === "fulfilled") {
onResolved(this.PromiseResult)
}
if (this.PromiseState === "rejected") {
onRejected(this.PromiseResult)
}
}
7. 异步任务回调的执行
function Promise(executor) {
this.PromiseState = "pending"
this.PromiseResult = null
// 这里的this指向Promise对象
// console.log(this);
// 因为在resolve里面,this指向的是window不是Promise对象,所以应该预先保存实例对象的this值
const self = this
// 用于在异步任务回调中保存回调函数
this.callback = {}
function resolve(data) {
if (self.PromiseState !== "pending") return
// 这里的this指向window
// console.log(this); // 指向window
// console.log(self); // 指向promise对象
self.PromiseState = "fulfilled"
self.PromiseResult = data
// 执行成功的回调
if (self.callback.onResolved) {
self.callback.onResolved(data)
}
}
function reject(err) {
if (self.PromiseState !== "pending") return
self.PromiseState = "rejected"
self.PromiseResult = err
// 执行失败的回调
if (self.callback.onRejected) {
self.callback.onRejected(err)
}
}
// 捕获异常
try {
// 执行器函数是同步调用的
executor(resolve, reject)
} catch (error) {
// 调用reject函数修改Promise对象的状态和值
reject(error)
}
}
// 给Promise的原型上添加then方法
Promise.prototype.then = function (onResolved, onRejected) {
// 这里的this指向Promise对象
// console.log(this);
// 调用回调函数
if (this.PromiseState === "fulfilled") {
onResolved(this.PromiseResult)
}
if (this.PromiseState === "rejected") {
onRejected(this.PromiseResult)
}
// 异步任务回调
if (this.PromiseState === "pending") {
// 保存回调函数
this.callback = {
onResolved,
onRejected
}
}
}
如果Promise的构造器中有异步代码,这时要先执行回调函数,再改变Promise状态,所以要先将回调函数保存下来,等待异步任务执行完改变Promise状态再执行回调函数。首先创建一个callback
对象用用于保存回调函数,在then方法中对回调函数进行保存,然后在resolve和reject函数中执行保存的回调函数。
8. 指定多个回调的实现
function Promise(executor) {
this.PromiseState = "pending"
this.PromiseResult = null
// 这里的this指向Promise对象
// console.log(this);
// 因为在resolve里面,this指向的是window不是Promise对象,所以应该预先保存实例对象的this值
const self = this
// 用于在异步任务回调中保存回调函数
this.callbacks = []
function resolve(data) {
if (self.PromiseState !== "pending") return
// 这里的this指向window
// console.log(this); // 指向window
// console.log(self); // 指向promise对象
self.PromiseState = "fulfilled"
self.PromiseResult = data
// 执行成功的回调
self.callbacks.forEach(item => {
item.onResolved(data)
})
}
function reject(err) {
if (self.PromiseState !== "pending") return
self.PromiseState = "rejected"
self.PromiseResult = err
// 执行失败的回调
self.callbacks.forEach(item => {
item.onRejected(err)
})
}
// 捕获异常
try {
// 执行器函数是同步调用的
executor(resolve, reject)
} catch (error) {
// 调用reject函数修改Promise对象的状态和值
reject(error)
}
}
// 给Promise的原型上添加then方法
Promise.prototype.then = function (onResolved, onRejected) {
// 这里的this指向Promise对象
// console.log(this);
// 调用回调函数
if (this.PromiseState === "fulfilled") {
onResolved(this.PromiseResult)
}
if (this.PromiseState === "rejected") {
onRejected(this.PromiseResult)
}
// 异步任务回调
if (this.PromiseState === "pending") {
// 保存回调函数
this.callbacks.push({
onResolved,
onRejected
})
}
}
将多个回调保存在一个数组中(防止覆盖),循环执行。
9. 同步修改状态then方法结果返回
function Promise(executor) {
this.PromiseState = "pending"
this.PromiseResult = null
// 这里的this指向Promise对象
// console.log(this);
// 因为在resolve里面,this指向的是window不是Promise对象,所以应该预先保存实例对象的this值
const self = this
// 用于在异步任务回调中保存回调函数
this.callbacks = []
function resolve(data) {
if (self.PromiseState !== "pending") return
// 这里的this指向window
// console.log(this); // 指向window
// console.log(self); // 指向promise对象
self.PromiseState = "fulfilled"
self.PromiseResult = data
// 执行成功的回调
self.callbacks.forEach(item => {
item.onResolved(data)
})
}
function reject(err) {
if (self.PromiseState !== "pending") return
self.PromiseState = "rejected"
self.PromiseResult = err
// 执行失败的回调
self.callbacks.forEach(item => {
item.onRejected(err)
})
}
// 捕获异常
try {
// 执行器函数是同步调用的
executor(resolve, reject)
} catch (error) {
// 调用reject函数修改Promise对象的状态和值
reject(error)
}
}
// 给Promise的原型上添加then方法
Promise.prototype.then = function (onResolved, onRejected) {
// 返回一个Promise对象
return new Promise((resolve, reject) => {
// 这里的this指向Promise对象
// console.log(this);
// 调用回调函数
if (this.PromiseState === "fulfilled") {
try {
// 获取回调函数的执行结果
let result = onResolved(this.PromiseResult)
// 判断执行结果类型
if (result instanceof Promise) {
// 结果为Promise对象
result.then(res => {
resolve(res)
}, err => {
reject(err)
})
} else {
// 结果状态为成功
resolve(result)
}
} catch (error) {
reject(error)
}
}
if (this.PromiseState === "rejected") {
onRejected(this.PromiseResult)
}
// 异步任务回调
if (this.PromiseState === "pending") {
// 保存回调函数
this.callbacks.push({
onResolved,
onRejected
})
}
})
}
10. 异步修改状态then方法结果返回
function Promise(executor) {
this.PromiseState = "pending"
this.PromiseResult = null
// 这里的this指向Promise对象
// console.log(this);
// 因为在resolve里面,this指向的是window不是Promise对象,所以应该预先保存实例对象的this值
const self = this
// 用于在异步任务回调中保存回调函数
this.callbacks = []
function resolve(data) {
if (self.PromiseState !== "pending") return
// 这里的this指向window
// console.log(this); // 指向window
// console.log(self); // 指向promise对象
self.PromiseState = "fulfilled"
self.PromiseResult = data
// 执行成功的回调
self.callbacks.forEach(item => {
item.onResolved(data)
})
}
function reject(err) {
if (self.PromiseState !== "pending") return
self.PromiseState = "rejected"
self.PromiseResult = err
// 执行失败的回调
self.callbacks.forEach(item => {
item.onRejected(err)
})
}
// 捕获异常
try {
// 执行器函数是同步调用的
executor(resolve, reject)
} catch (error) {
// 调用reject函数修改Promise对象的状态和值
reject(error)
}
}
// 给Promise的原型上添加then方法
Promise.prototype.then = function (onResolved, onRejected) {
const self = this
// 返回一个Promise对象
return new Promise((resolve, reject) => {
// 这里的this指向Promise对象
// console.log(this);
// 封装回调函数执行结果
function callback(type) {
try {
// 获取回调函数的执行结果
let result = type(self.PromiseResult)
// 判断执行结果类型
if (result instanceof Promise) {
// 结果为Promise对象
result.then(res => {
resolve(res)
}, err => {
reject(err)
})
} else {
// 结果状态为成功
resolve(result)
}
} catch (error) {
reject(error)
}
}
// 调用回调函数
if (this.PromiseState === "fulfilled") {
callback(onResolved)
}
if (this.PromiseState === "rejected") {
callback(onRejected)
}
// 异步任务回调
if (this.PromiseState === "pending") {
// 保存回调函数
this.callbacks.push({
onResolved: function () {
callback(onResolved)
},
onRejected: function () {
callback(onRejected)
}
})
}
})
}
11. catch方法封装
function Promise(executor) {
this.PromiseState = "pending"
this.PromiseResult = null
// 这里的this指向Promise对象
// console.log(this);
// 因为在resolve里面,this指向的是window不是Promise对象,所以应该预先保存实例对象的this值
const self = this
// 用于在异步任务回调中保存回调函数
this.callbacks = []
function resolve(data) {
if (self.PromiseState !== "pending") return
// 这里的this指向window
// console.log(this); // 指向window
// console.log(self); // 指向promise对象
self.PromiseState = "fulfilled"
self.PromiseResult = data
// 执行成功的回调
self.callbacks.forEach(item => {
item.onResolved(data)
})
}
function reject(err) {
if (self.PromiseState !== "pending") return
self.PromiseState = "rejected"
self.PromiseResult = err
// 执行失败的回调
self.callbacks.forEach(item => {
item.onRejected(err)
})
}
// 捕获异常
try {
// 执行器函数是同步调用的
executor(resolve, reject)
} catch (error) {
// 调用reject函数修改Promise对象的状态和值
reject(error)
}
}
// 给Promise的原型上添加then方法
Promise.prototype.then = function (onResolved, onRejected) {
const self = this
// 判断回调函数的参数
if (typeof onRejected !== "function") {
onRejected = (err => {
throw err
})
}
if (typeof onResolved !== "function") {
onResolved = (res => {
return res
})
}
// 返回一个Promise对象
return new Promise((resolve, reject) => {
// 这里的this指向Promise对象
// console.log(this);
// 封装回调函数执行结果
function callback(type) {
try {
// 获取回调函数的执行结果
let result = type(self.PromiseResult)
// 判断执行结果类型
if (result instanceof Promise) {
// 结果为Promise对象
result.then(res => {
resolve(res)
}, err => {
reject(err)
})
} else {
// 结果状态为成功
resolve(result)
}
} catch (error) {
reject(error)
}
}
// 调用回调函数
if (this.PromiseState === "fulfilled") {
callback(onResolved)
}
if (this.PromiseState === "rejected") {
callback(onRejected)
}
// 异步任务回调
if (this.PromiseState === "pending") {
// 保存回调函数
this.callbacks.push({
onResolved: function () {
callback(onResolved)
},
onRejected: function () {
callback(onRejected)
}
})
}
})
}
// 添加catch方法
Promise.prototype.catch = function (onRejected) {
return this.then(undefined, onRejected)
}
12. resolve方法封装
function Promise(executor) {
this.PromiseState = "pending"
this.PromiseResult = null
// 这里的this指向Promise对象
// console.log(this);
// 因为在resolve里面,this指向的是window不是Promise对象,所以应该预先保存实例对象的this值
const self = this
// 用于在异步任务回调中保存回调函数
this.callbacks = []
function resolve(data) {
if (self.PromiseState !== "pending") return
// 这里的this指向window
// console.log(this); // 指向window
// console.log(self); // 指向promise对象
self.PromiseState = "fulfilled"
self.PromiseResult = data
// 执行成功的回调
self.callbacks.forEach(item => {
item.onResolved(data)
})
}
function reject(err) {
if (self.PromiseState !== "pending") return
self.PromiseState = "rejected"
self.PromiseResult = err
// 执行失败的回调
self.callbacks.forEach(item => {
item.onRejected(err)
})
}
// 捕获异常
try {
// 执行器函数是同步调用的
executor(resolve, reject)
} catch (error) {
// 调用reject函数修改Promise对象的状态和值
reject(error)
}
}
// 给Promise的原型上添加then方法
Promise.prototype.then = function (onResolved, onRejected) {
const self = this
// 判断回调函数的参数
if (typeof onRejected !== "function") {
onRejected = (err => {
throw err
})
}
if (typeof onResolved !== "function") {
onResolved = (res => {
return res
})
}
// 返回一个Promise对象
return new Promise((resolve, reject) => {
// 这里的this指向Promise对象
// console.log(this);
// 封装回调函数执行结果
function callback(type) {
try {
// 获取回调函数的执行结果
let result = type(self.PromiseResult)
// 判断执行结果类型
if (result instanceof Promise) {
// 结果为Promise对象
result.then(res => {
resolve(res)
}, err => {
reject(err)
})
} else {
// 结果状态为成功
resolve(result)
}
} catch (error) {
reject(error)
}
}
// 调用回调函数
if (this.PromiseState === "fulfilled") {
callback(onResolved)
}
if (this.PromiseState === "rejected") {
callback(onRejected)
}
// 异步任务回调
if (this.PromiseState === "pending") {
// 保存回调函数
this.callbacks.push({
onResolved: function () {
callback(onResolved)
},
onRejected: function () {
callback(onRejected)
}
})
}
})
}
// 添加catch方法
Promise.prototype.catch = function (onRejected) {
return this.then(undefined, onRejected)
}
// 添加resolve方法
Promise.resolve = function (res) {
return new Promise((resolve, reject) => {
if (res instanceof Promise) {
res.then(data => {
resolve(data)
}).catch(err => {
reject(err);
})
} else {
// 如果不是promise对象,将状态设置为成功
resolve(res)
}
})
}
13. reject方法封装
function Promise(executor) {
this.PromiseState = "pending"
this.PromiseResult = null
// 这里的this指向Promise对象
// console.log(this);
// 因为在resolve里面,this指向的是window不是Promise对象,所以应该预先保存实例对象的this值
const self = this
// 用于在异步任务回调中保存回调函数
this.callbacks = []
function resolve(data) {
if (self.PromiseState !== "pending") return
// 这里的this指向window
// console.log(this); // 指向window
// console.log(self); // 指向promise对象
self.PromiseState = "fulfilled"
self.PromiseResult = data
// 执行成功的回调
self.callbacks.forEach(item => {
item.onResolved(data)
})
}
function reject(err) {
if (self.PromiseState !== "pending") return
self.PromiseState = "rejected"
self.PromiseResult = err
// 执行失败的回调
self.callbacks.forEach(item => {
item.onRejected(err)
})
}
// 捕获异常
try {
// 执行器函数是同步调用的
executor(resolve, reject)
} catch (error) {
// 调用reject函数修改Promise对象的状态和值
reject(error)
}
}
// 给Promise的原型上添加then方法
Promise.prototype.then = function (onResolved, onRejected) {
const self = this
// 判断回调函数的参数
if (typeof onRejected !== "function") {
onRejected = (err => {
throw err
})
}
if (typeof onResolved !== "function") {
onResolved = (res => {
return res
})
}
// 返回一个Promise对象
return new Promise((resolve, reject) => {
// 这里的this指向Promise对象
// console.log(this);
// 封装回调函数执行结果
function callback(type) {
try {
// 获取回调函数的执行结果
let result = type(self.PromiseResult)
// 判断执行结果类型
if (result instanceof Promise) {
// 结果为Promise对象
result.then(res => {
resolve(res)
}, err => {
reject(err)
})
} else {
// 结果状态为成功
resolve(result)
}
} catch (error) {
reject(error)
}
}
// 调用回调函数
if (this.PromiseState === "fulfilled") {
callback(onResolved)
}
if (this.PromiseState === "rejected") {
callback(onRejected)
}
// 异步任务回调
if (this.PromiseState === "pending") {
// 保存回调函数
this.callbacks.push({
onResolved: function () {
callback(onResolved)
},
onRejected: function () {
callback(onRejected)
}
})
}
})
}
// 添加catch方法
Promise.prototype.catch = function (onRejected) {
return this.then(undefined, onRejected)
}
// 添加resolve方法
Promise.resolve = function (res) {
return new Promise((resolve, reject) => {
if (res instanceof Promise) {
res.then(data => {
resolve(data)
}).catch(err => {
reject(err);
})
} else {
// 如果不是promise对象,将状态设置为成功
resolve(res)
}
})
}
// 添加reject方法
Promise.reject = function (err) {
return new Promise((resolve, reject) => {
reject(err)
})
}
14. all方法封装
function Promise(executor) {
this.PromiseState = "pending"
this.PromiseResult = null
// 这里的this指向Promise对象
// console.log(this);
// 因为在resolve里面,this指向的是window不是Promise对象,所以应该预先保存实例对象的this值
const self = this
// 用于在异步任务回调中保存回调函数
this.callbacks = []
function resolve(data) {
if (self.PromiseState !== "pending") return
// 这里的this指向window
// console.log(this); // 指向window
// console.log(self); // 指向promise对象
self.PromiseState = "fulfilled"
self.PromiseResult = data
// 执行成功的回调
self.callbacks.forEach(item => {
item.onResolved(data)
})
}
function reject(err) {
if (self.PromiseState !== "pending") return
self.PromiseState = "rejected"
self.PromiseResult = err
// 执行失败的回调
self.callbacks.forEach(item => {
item.onRejected(err)
})
}
// 捕获异常
try {
// 执行器函数是同步调用的
executor(resolve, reject)
} catch (error) {
// 调用reject函数修改Promise对象的状态和值
reject(error)
}
}
// 给Promise的原型上添加then方法
Promise.prototype.then = function (onResolved, onRejected) {
const self = this
// 判断回调函数的参数
if (typeof onRejected !== "function") {
onRejected = (err => {
throw err
})
}
if (typeof onResolved !== "function") {
onResolved = (res => {
return res
})
}
// 返回一个Promise对象
return new Promise((resolve, reject) => {
// 这里的this指向Promise对象
// console.log(this);
// 封装回调函数执行结果
function callback(type) {
try {
// 获取回调函数的执行结果
let result = type(self.PromiseResult)
// 判断执行结果类型
if (result instanceof Promise) {
// 结果为Promise对象
result.then(res => {
resolve(res)
}, err => {
reject(err)
})
} else {
// 结果状态为成功
resolve(result)
}
} catch (error) {
reject(error)
}
}
// 调用回调函数
if (this.PromiseState === "fulfilled") {
callback(onResolved)
}
if (this.PromiseState === "rejected") {
callback(onRejected)
}
// 异步任务回调
if (this.PromiseState === "pending") {
// 保存回调函数
this.callbacks.push({
onResolved: function () {
callback(onResolved)
},
onRejected: function () {
callback(onRejected)
}
})
}
})
}
// 添加catch方法
Promise.prototype.catch = function (onRejected) {
return this.then(undefined, onRejected)
}
// 添加resolve方法
Promise.resolve = function (res) {
return new Promise((resolve, reject) => {
if (res instanceof Promise) {
res.then(data => {
resolve(data)
}).catch(err => {
reject(err);
})
} else {
// 如果不是promise对象,将状态设置为成功
resolve(res)
}
})
}
// 添加reject方法
Promise.reject = function (err) {
return new Promise((resolve, reject) => {
reject(err)
})
}
// 添加all方法
Promise.all = function (promises) {
return new Promise((resolve, reject) => {
// 声明一个计数变量
let count = 0
// 成功结果数组
let arr = []
// 遍历
for (let i = 0; i < promises.length; i++) {
promises[i].then(res => {
count += 1
arr[i] = res
if (count === promises.length) {
resolve(arr)
}
}).catch(err => {
reject(err)
})
}
})
}
15. race方法封装
function Promise(executor) {
this.PromiseState = "pending"
this.PromiseResult = null
// 这里的this指向Promise对象
// console.log(this);
// 因为在resolve里面,this指向的是window不是Promise对象,所以应该预先保存实例对象的this值
const self = this
// 用于在异步任务回调中保存回调函数
this.callbacks = []
function resolve(data) {
if (self.PromiseState !== "pending") return
// 这里的this指向window
// console.log(this); // 指向window
// console.log(self); // 指向promise对象
self.PromiseState = "fulfilled"
self.PromiseResult = data
// 执行成功的回调
self.callbacks.forEach(item => {
item.onResolved(data)
})
}
function reject(err) {
if (self.PromiseState !== "pending") return
self.PromiseState = "rejected"
self.PromiseResult = err
// 执行失败的回调
self.callbacks.forEach(item => {
item.onRejected(err)
})
}
// 捕获异常
try {
// 执行器函数是同步调用的
executor(resolve, reject)
} catch (error) {
// 调用reject函数修改Promise对象的状态和值
reject(error)
}
}
// 给Promise的原型上添加then方法
Promise.prototype.then = function (onResolved, onRejected) {
const self = this
// 判断回调函数的参数
if (typeof onRejected !== "function") {
onRejected = (err => {
throw err
})
}
if (typeof onResolved !== "function") {
onResolved = (res => {
return res
})
}
// 返回一个Promise对象
return new Promise((resolve, reject) => {
// 这里的this指向Promise对象
// console.log(this);
// 封装回调函数执行结果
function callback(type) {
try {
// 获取回调函数的执行结果
let result = type(self.PromiseResult)
// 判断执行结果类型
if (result instanceof Promise) {
// 结果为Promise对象
result.then(res => {
resolve(res)
}, err => {
reject(err)
})
} else {
// 结果状态为成功
resolve(result)
}
} catch (error) {
reject(error)
}
}
// 调用回调函数
if (this.PromiseState === "fulfilled") {
callback(onResolved)
}
if (this.PromiseState === "rejected") {
callback(onRejected)
}
// 异步任务回调
if (this.PromiseState === "pending") {
// 保存回调函数
this.callbacks.push({
onResolved: function () {
callback(onResolved)
},
onRejected: function () {
callback(onRejected)
}
})
}
})
}
// 添加catch方法
Promise.prototype.catch = function (onRejected) {
return this.then(undefined, onRejected)
}
// 添加resolve方法
Promise.resolve = function (res) {
return new Promise((resolve, reject) => {
if (res instanceof Promise) {
res.then(data => {
resolve(data)
}).catch(err => {
reject(err);
})
} else {
// 如果不是promise对象,将状态设置为成功
resolve(res)
}
})
}
// 添加reject方法
Promise.reject = function (err) {
return new Promise((resolve, reject) => {
reject(err)
})
}
// 添加all方法
Promise.all = function (promises) {
return new Promise((resolve, reject) => {
// 声明一个计数变量
let count = 0
// 成功结果数组
let arr = []
// 遍历
for (let i = 0; i < promises.length; i++) {
promises[i].then(res => {
count += 1
arr[i] = res
if (count === promises.length) {
resolve(arr)
}
}).catch(err => {
reject(err)
})
}
})
}
// 添加race方法
Promise.race = function (promises) {
return new Promise((resolve, reject) => {
// 遍历
for (let i = 0; i < promises.length; i++) {
promises[i].then(res => {
resolve(res)
}).catch(err => {
reject(err)
})
}
})
}
16. then方法的回调异步执行
function Promise(executor) {
this.PromiseState = "pending"
this.PromiseResult = null
// 这里的this指向Promise对象
// console.log(this);
// 因为在resolve里面,this指向的是window不是Promise对象,所以应该预先保存实例对象的this值
const self = this
// 用于在异步任务回调中保存回调函数
this.callbacks = []
function resolve(data) {
if (self.PromiseState !== "pending") return
// 这里的this指向window
// console.log(this); // 指向window
// console.log(self); // 指向promise对象
self.PromiseState = "fulfilled"
self.PromiseResult = data
setTimeout(() => {
// 执行成功的回调
self.callbacks.forEach(item => {
item.onResolved(data)
})
}, 0);
}
function reject(err) {
if (self.PromiseState !== "pending") return
self.PromiseState = "rejected"
self.PromiseResult = err
setTimeout(() => {
// 执行失败的回调
self.callbacks.forEach(item => {
item.onRejected(err)
})
}, 0);
}
// 捕获异常
try {
// 执行器函数是同步调用的
executor(resolve, reject)
} catch (error) {
// 调用reject函数修改Promise对象的状态和值
reject(error)
}
}
// 给Promise的原型上添加then方法
Promise.prototype.then = function (onResolved, onRejected) {
const self = this
// 判断回调函数的参数
if (typeof onRejected !== "function") {
onRejected = (err => {
throw err
})
}
if (typeof onResolved !== "function") {
onResolved = (res => {
return res
})
}
// 返回一个Promise对象
return new Promise((resolve, reject) => {
// 这里的this指向Promise对象
// console.log(this);
// 封装回调函数执行结果
function callback(type) {
try {
// 获取回调函数的执行结果
let result = type(self.PromiseResult)
// 判断执行结果类型
if (result instanceof Promise) {
// 结果为Promise对象
result.then(res => {
resolve(res)
}, err => {
reject(err)
})
} else {
// 结果状态为成功
resolve(result)
}
} catch (error) {
reject(error)
}
}
// 调用回调函数
if (this.PromiseState === "fulfilled") {
setTimeout(() => {
callback(onResolved)
}, 0);
}
if (this.PromiseState === "rejected") {
setTimeout(() => {
callback(onRejected)
}, 0);
}
// 异步任务回调
if (this.PromiseState === "pending") {
// 保存回调函数
this.callbacks.push({
onResolved: function () {
callback(onResolved)
},
onRejected: function () {
callback(onRejected)
}
})
}
})
}
// 添加catch方法
Promise.prototype.catch = function (onRejected) {
return this.then(undefined, onRejected)
}
// 添加resolve方法
Promise.resolve = function (res) {
return new Promise((resolve, reject) => {
if (res instanceof Promise) {
res.then(data => {
resolve(data)
}).catch(err => {
reject(err);
})
} else {
// 如果不是promise对象,将状态设置为成功
resolve(res)
}
})
}
// 添加reject方法
Promise.reject = function (err) {
return new Promise((resolve, reject) => {
reject(err)
})
}
// 添加all方法
Promise.all = function (promises) {
return new Promise((resolve, reject) => {
// 声明一个计数变量
let count = 0
// 成功结果数组
let arr = []
// 遍历
for (let i = 0; i < promises.length; i++) {
promises[i].then(res => {
count += 1
arr[i] = res
if (count === promises.length) {
resolve(arr)
}
}).catch(err => {
reject(err)
})
}
})
}
// 添加race方法
Promise.race = function (promises) {
return new Promise((resolve, reject) => {
// 遍历
for (let i = 0; i < promises.length; i++) {
promises[i].then(res => {
resolve(res)
}).catch(err => {
reject(err)
})
}
})
}
AJAX、Fetch、axios
AJAX
AJAX可以在不更新全局的情况下更新局部页面。通过在与服务器进行数据交换,可以是网页实现异步更新。
创建AJAX
// 1. 创建 XMLHttpRequest 实例
let xhr = XMLHttpRequest()
// 2. 打开和服务器的连接
xhr.open('get', 'URL')
// 3.发送
xhr.send()
// 4. 接收变化。
xhr.onreadystatechange = () => {
if(xhr.readyState == 4 && xhr.status == 200){ // readyState: ajax 状态,status:http 请求状态
console.log(xhr.responseText); //响应主体
}
}
- 创建
AJAX
实例:let xhr = new XMLHttpRequest()
- 打开请求,配置请求前的配置项:
xhr.open([http method], [url], [async], [userName], [userPass])
http methods
请求方式:post
,get
,delete
,put
,head
,options
,trace
,connect
url
:想服务器请求的路径async
:是否为异步请求userName
、userPass
:用户名与密码
- 发送请求:
XMLHttpRequest.send()
方法中如果 Ajax 请求是异步的则这个方法发送请求后就会返回,如果Ajax请求是同步的,那么请求必须知道响应后才会返回。 - 接收数据
AJAX的缺点:
- 本是针对MVC变成,不符合前端MVVM的浪潮
- 基于原生的XHR开发
- 配置和调用方式混乱
axios原理
axios是使用promise封装的ajax,它内部有两个拦截器,分别是request拦截器和response拦截器。
- 请求拦截器的作用是在请求发送之前进行一些操作,例如在每个请求体上加入token
- 响应拦截器的作用是接收到响应后做的一些操作,例如登录失败后需要重新登录跳转到登录页
axios的特点
- 由浏览器端发起请求
- 支持promise API
- 监听请求和返回
- 更好的格式化,自动将数据转换为json数据
- 安全性更高,可抵御XSRF攻击
axios常用的方法
axios常用的方法有get
、post
、put
、patch
、delete
等。其中get
和post
返回的都是promise
对象,可以使用promise
方法
axios.get(url[, config])
:get请求用于列表和信息查询
axios.get('apiURL', {
param: {
id: 1
}
// param 中的的键值对最终会 ? 的形式,拼接到请求的链接上,发送到服务器。
}).then(res => {
console.log(res);
})
.catch( error => {
console.log(error)
}
axios.delete(url[, config])
:删除
axios.delete('apiURL', {
params: {
id: 1
},
timeout: 1000
})
axios.post(url[, data[, config]])
:post请求用于信息的添加
axios.post('apiURL',{
user: '小新',
age: 18
}).then( res => {
console.log(res);
})
.catch( error => {
console.log(error)
}
axios.put(url[, data[, config]])
:更新操作
axios.put('apiURL', {
name: '小新',
})
axios.patch(url[, data[, config]])
:更新操作
axios.patch('apiURL', {
id: 13,
},{
timeout: 1000,
})
put和patch的区别
patch
方法用来更新局部资源,假设我们有一个UserInfo,里面有userId,userName,userGender等10个字段。可你的编辑功能因为需求,在某个特别的页面里只能修改userName,这个时候就可以使用patch
。
put
也适用于更新数据,但必须提供完整的资源对象。
axios相关配置
- url:用于请求服务器的url
- method:请求方法,默认为get
- baseURL:会自动加到url前面
- proxy:用于配置代理
- transformRequest:允许在服务器发送请求之前修改请求数据
fetch
fetch
是http请求数据的方式,它使用Promise,但不使用回调函数。fetch
采用模块化设计,通过数据流处理数据,对于请求大文件或网速慢的情况相当有用。默认情况下fetch不会接收或发送cookies。
Fetch、ajax与axios的区别
- 传统的ajax利用的是
HMLHttpRequest这个对象
,和后端进行交互。而JQury ajax
是对原生XHR
的封装,多请求间有嵌套的话就会出现回调地狱的问题。 axios
使用promise
封装XHR
,解决了回调地狱的问题。- 而
Fetch
没有使用XHR
,使用的是promise
Fetch和Ajax比有什么优点
Fetch
使用的是promise
,方便使用异步,没有回调地狱的问题。