一,Promise到底是个啥?
promise是一个构造函数,它用来封装异步操作,可以有效解决回调地狱问题
以下使用promise封装ajax请求
var btn = document.getElementById('btn')
btn.onclick = function () {
const p = new Promise((resolve, reject) => {
// 创建对象
const xhr = new XMLHttpRequest
// 初始化
xhr.open('GET', 'https://xxxxx')
// 发送
xhr.send()
// 处理相应结果
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(xhr.response)
} else {
reject(xhr.status)
}
}
}
})
p.then(value => {
console.log(value);
}, reason => {
console.log(reason);
})
}
二, Promise有三个状态:pendding,resolved,rejeced,那么如何改变promise的状态呢?
1,执行resolve()会将状态变为resolved
2,执行reject()会将状态变为rejected
3,抛出错误 thow会将状态变为rejected
三,如果使用then方法指定多个成功、失败的回调,这些回调都会执行吗?
都会执行!!!
四,改变promise状态和<指定>回调函数谁先谁后?
这取决于resolve()/reject()和then()在那调用,这涉及到js事件循环的知识
五,then方法返回的结果由什么决定?
由then方法指定的回调函数的执行结果决定的
六,promise异常穿透
在使用promise的then的链式调用的时候,可以在最后指定失败的回调,前面任何操作的异常,都会传到最后失败的回调中处理
七,怎么中断promise链条?
在链式调用中返回一个pending状态的promise对象即可
八,手写Promise
// Promise是一个构造函数,可以封装异步的任务,并且对结果进行处理
// promise支持链式调用,可以用来解决回调地狱的问题,在指定回调和错误处理方面更加灵活
function my_Promise(executor) {
this.promiseStatus = 'pending'
this.promiseResult = null
// 如果给一个promise对象指定多个回调函数,当状态改变时,这些回调都会生效
this.callbacks = []
// 因为执行resolve/reject的时候函数的this指向window而不是实例对象,所以需要保存这里的this
const self = this
function resolve(data) {
if (self.promiseStatus !== 'pending') return
self.promiseStatus = 'resolved'
self.promiseResult = data
self.callbacks.forEach(item => {
item.onResolved(data)
});
}
function reject(data) {
if (self.promiseStatus !== 'pending') return
self.promiseStatus = 'rejected'
self.promiseResult = data
self.callbacks.forEach(item => {
item.onReject(data)
});
}
try {
executor(resolve, reject)
} catch (error) {
reject(error)
}
}
my_Promise.prototype.then = function (onResolved, onReject) {
if (this.promiseStatus === 'resolved') onResolved(this.promiseResult)
if (this.promiseStatus === 'rejected') onReject(this.promiseResult)
if (this.promiseStatus === 'pending')
this.callbacks.push({ onResolved, onReject })
}
// 测试
// var p = new my_Promise((resolve, reject) => {
// setTimeout(() => {
// resolve('okkkkkk')
// }, 2000);
// })
// p.then(value => {
// console.log(value);
// }, reason => {
// console.warn(reason);
// })
// p.then(value => {
// alert(value);
// }, reason => {
// console.warn(reason);
// })
// Promise.all方法:可以将多个Promise实例包装成一个新的Promise实例。
// 同时,成功和失败的返回值是不同的,成功的时候返回的是一个结果数组,而失败的时候则返回最先被reject失败状态的值。
my_Promise.all = function (promises) {
return new my_Promise((resolve, reject) => {
var arr = []
promises.forEach((item, index) => {
item.then(value => {
arr[index] = value
if (arr.length === promises.length) {
resolve(arr)
}
}, reason => {
reject(reason)
})
})
})
}
// // 测试
// var p1 = new my_Promise((resolve, reject) => {
// resolve('okk')
// })
// var p2 = new my_Promise((resolve, reject) => {
// resolve('hello')
// })
// var p3 = new my_Promise((resolve, reject) => {
// reject('kang')
// })
// var pros = [p1, p2, p3]
// console.log(my_Promise.all(pros));
// Promise.race方法:Promse.race就是赛跑的意思,意思就是说,Promise.race([p1, p2, p3])
// 里面哪个结果获得的快,就返回那个结果
my_Promise.race = function (promises) {
return new Promise((resolve, reject) => {
for (var i = 0; i < promises.length; i++) {
promises[i].then(value => {
resolve(value)
}, reason => {
reject(reason)
})
}
})
}
// let p1 = new Promise((resolve, reject) => {
// setTimeout(() => {
// resolve('success')
// }, 1000)
// })
// let p2 = new Promise((resolve, reject) => {
// setTimeout(() => {
// reject('failed')
// }, 5000)
// })
// // 测试
// my_Promise.race([p1, p2]).then((result) => {
// console.log(result)
// }).catch((error) => {
// console.log(error) // 打开的是 'failed'
// })
Promise.all()
接收一个由promise组成的数组(如果数组里不是promise,那么会调用Promise.resolve()将其转化为Promise),返回的结果是一个Promise,状态由传进来的这些promise状态决定,
- 他们的状态全是fullfilled那Promise.all返回的promise状态就是就是fulfilled,值是传进来的promise数组返回的值,顺序跟传进来的顺序一致。
- 只要有一个是failed,那么Promise.all()返回的promise的状态就是failed,值就是第一个失败了的promise的值
Promise.race()
接受由多个promise实例构成的数组(如果数组里不是promise,那么会调用Promise.resolve()将其转化为Promise)返回的结果也是一个promise实例,跟传进来的promise实例中第一个改变状态的Promise保持一致。
async await
async/await是Generator和yield的语法糖
async相当于Generator,await相当于yield
Generator方式的函数里面代码会分段执行,看到yield就分一段
使用async/await比较方便,代码清晰
async/await也是解决异步的一个办法,背后原理就是Generator和yield,当一个函数前面加上了async,这个函数就变成了异步的函数
await必须要在async修饰的函数内部使用,他会阻塞后面的代码,等到主线程的任务执行完了之后才会回来执行
async,await 代码输出:
async function async1() {
console.log("async1 start");
await async2();
console.log("async1 end");
}
async function async2() {
console.log("async2");
}
async1();
console.log('start')
答案:
‘async1 start’
‘async2’
‘start’
‘async1 end’
过程分析:
首先一进来是创建了两个函数的,我们先不看函数的创建位置,而是看它的调用位置
发现async1函数被调用了,然后去看看调用的内容
执行函数中的同步代码async1 start,之后碰到了await,它会阻塞async1后面代码的执行,因此会先去执行async2中的同步代码async2,然后跳出async1
跳出async1函数后,执行同步代码start
在一轮宏任务全部执行完之后,再来执行刚刚await后面的内容async1 end。
在这里,你可以理解为紧跟着await后面的语句相当于放到了new Promise中,下一行及之后的语句相当于放在Promise.then中
async function async1 () {
console.log('async1 start');
await new Promise(resolve => {
console.log('promise1')
})
console.log('async1 success');
return 'async1 end'
}
console.log('srcipt start')
async1().then(res => console.log(res))
console.log('srcipt end')
- 在async1中await后面的Promise是没有返回值的,也就是它的状态始终是pending状态,因此相当于一直在await,await,await却始终没有响应…
- async函数中抛出了错误或者reject(),则终止错误结果,不会继续向下执行。可以用try catch捕获