1. 对 Promise 的了解
(1)Promise的用途:为了解决命名不规范、回调地狱使得代码复杂、难以进行错误处理等问题提出的规范,它可以规范回调的名字或顺序、拒绝回调地狱、增加代码可读性,方便查找错误。
(2)如何创建一个Promise
function fn(){
return new Promise((resolve, reject)=>{
成功时调用 resolve(data)
失败时调用 reject(reason)
})
}
(3)如何使用 Promise.prototype.then
then() 方法返回一个 Promise 。它最多需要有两个参数:Promise 的成功和失败情况的回调函数。
例子是用Promis手写的Ajax
ajax = (method, url, options) => {
return new Promise((resolve, reject) => {
const { success, fail } = options // 析构赋值
const request = new XMLHttpRequest()
request.open(method, url)
request.onreadystatechange = () => {
if (request.readyState === 4) {
// 成功就调用success,失败就调用fail
if (request.status < 400) {
resolve.call(null, request.response)
} else if (request.status >= 400) {
reject.call(null, request, request.status)
}
}
}
request.send()
})
}
ajax("get", "/xxx")
.then((response) => {},
(request) => {})
// then 的都一个参数就是success,第二个参数就是fail。另:promise规定成功还是失败都只传一个参数
const promise1 = fn() // 得到 promise1 对象
fn().then(success, fail).then(success2, fail2).catch(fail3)
// 或者
// promise1.then(success, fail).then(success2, fail2).catch(fail3)
// 均可
(4)如何使用 Promise.all
Promise.all可以将多个Promise实例包装成一个新的Promise实例。同时,成功和失败的返回值是不同的,成功的时候返回的是一个结果数组,失败时返回最先被reject失败状态的值。
Promise.all([promise1, promise2])
并行,等待所有 promise 成功。
如果都成功了,则 all 对应的 promise 也成功;如果有一个失败了,则 all 对应的 promise 失败。
let p1 = new Promise((resolve, reject) => {
resolve('成功了')
})
let p2 = new Promise((resolve, reject) => {
resolve('success')
})
let p3 = Promse.reject('失败')
Promise.all([p1, p2]).then((result) => {
console.log(result) //['成功了', 'success']
}).catch((error) => {
console.log(error)
})
Promise.all([p1,p3,p2]).then((result) => {
console.log(result)
}).catch((error) => {
console.log(error) // 失败了,打出 '失败'
})
需要特别注意的是,Promise.all获得的成功结果的数组里面的数据顺序和Promise.all接收到的数组顺序是一致的,即p1的结果在前,即便p1的结果获取的比p2要晚。这带来了一个绝大的好处:在前端开发请求数据的过程中,偶尔会遇到发送多个请求并根据请求顺序获取和使用数据的场景,使用Promise.all毫无疑问可以解决这个问题。
(5)如何使用 Promise.race
顾名思义,Promse.race就是赛跑的意思,意思就是说,Promise.race([p1, p2, p3])里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。
Promise.race([promise1, promise2])
返回一个 promise,一旦数组中的某个promise解决或拒绝,返回的 promise就会解决或拒绝。
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success')
},1000)
})
let p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('failed')
}, 500)
})
Promise.race([p1, p2]).then((result) => {
console.log(result)
}).catch((error) => {
console.log(error) // 打开的是 'failed'
})
适用场景例如多台服务器部署了同样的服务端代码,可以在race 中写上所有服务器中的查询商品列表的接口地址,哪个服务器响应快,就从哪个服务器拿数据。
2. 跨域
- 源 = 协议 + 域名 + 端口号。如果两个url的协议、域名、端口号完全一致,那么这两个url就是同源的。
例如https://baidu.com 、 https://www.baidu.com就是是不同源的 - 跨域,是指浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对JavaScript实施的安全限制。
- JSONP跨域
我们在跨域时由于当前浏览器不支持或某种原因无法使用CORS时,我们必须使用另外一种方式来跨域。于是我们在当前网站创建一个script标签去请求一个另一个网站的js,js里面会携带一些数据,然后在我们的网站中调用一个全局函数并运行,就可以获得这些数据。
优点:
(1)兼容IE。
(2)可以跨域
缺点:
(1)由于他是script标签,所以他读不到AJAX那么精确的状态,拿不到状态码和header
(2)由于他是script标签,所以他只能发送get请求,不支持post - CROS跨域
CORS是一个W3C标准,全称是“跨域资源共享”,允许浏览器像跨院服务器发出 XMLHttpRequest 请求,克服了AJAX只能同源使用的限制。
CORS跨域分为简单请求和复杂请求两种。
4.1 简单请求:顾名思义是相对简单的请求,满足一下条件的请求被称为简单请求。
- 请求方法
GET
POST
HEATD - 字段
Accept
Accept-Language
Content-Language
Content-Type - Content-Type 的值
text/plain
multipart/form-data
application/x-www-form-urlencoded - 实现过程
当使用 XMLHttpRequest发送请求时,浏览器发现该请求不符合同源策略,会自动给该请求加一个请求头:Origin,并将请求发送。服务器端收到请求后,如果确定接受请求则在返回结果中加入一个响应头:Access-Control-Allow-Origin: <origin> | *
; 浏览器收到响应后判断该相应头中是否包含 Origin 的值,如果有则浏览器会处理响应,我们就可以拿到响应数据,如果不包含浏览器直接驳回,这时我们无法拿到响应数据。
整个CORS通信过程,都是浏览器自动完成,不需要用户参。
实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。