Ajax VS Promise|精选博客
Posted 饥人谷前端
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Ajax VS Promise|精选博客相关的知识,希望对你有一定的参考价值。
这里有原生的 ajax,有 jQuery + ajax
这里有原生的 Promise,有 jQuery + promise
一、用 ajax 发送请求
新建如图所示的目录结构及文件:
arr.txt 文件中写入数组,如:
[1, 2, 3, 4, 5, 6, 7]
json.txt 文件中写入 json,如:
{
"a": "12",
"b": "我是董董",
"c": "true"
}
接下来,在 index.html 中,使用原生 ajax 请求 data 目录中的两个文件的内容:
var xhr1 = new XMLHttpRequest()
xhr1.open('GET', './data/json.txt')
xhr1.onreadystatechange = function () {
if (xhr1.readyState === 4 && xhr1.status === 200) { // 这里没有考虑其他情况
console.log('成功了')
console.log(xhr1.responseText)
} else {
// console.log('失败了')
}
}
xhr1.send()
var xhr2 = new XMLHttpRequest()
xhr2.open('GET', './data/arr.txt')
xhr2.onreadystatechange = function () {
if (xhr2.readyState === 4 && xhr2.status === 200) {
console.log('成功了')
console.log(xhr2.responseText)
} else {
// console.log('失败了')
}
}
xhr2.send()
换句话说,你应该安装一个 http-server 工具:
npm install http-server // 安装
http-server . -c-1 // 使用
然后根据提示,打开 url 即可。
现在,浏览器控制台中可以看到:
但是上面的 ajax 代码有冗余,所以封装一下:
function sendAjax(url, success, error) {
var xhr = new XMLHttpRequest()
xhr.open('GET', url)
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
var data = xhr.response
success(data) // 如果成功执行 success
} else {
error() // 如果失败执行 error
}
}
xhr.send()
}
sendAjax('./data/arr.txt', function (data) {
console.log('成功了')
console.log(data)
}, function () {
// console.log('失败了')
})
sendAjax('./data/json.txt', function (data) {
console.log('成功了')
console.log(data)
}, function () {
// console.log('失败了')
})
控制台:
这样,我们发送 ajax 请求似乎就变得简单了些。
但是,如果要求是,必须请求 arr.txt 成功后,才能请求 json.txt 的话,情况就慢慢复杂起来,你需要像下面这样发送请求:
sendAjax('./data/arr.txt', function (data) {
console.log('成功了')
console.log(data)
sendAjax('./data/json.txt', function (data) {
console.log('成功了')
console.log(data)
}, function () {
// console.log('失败了')
})
}, function () {
// console.log('失败了')
})
如果 arr.txt 请求未成功,比如我们把 arr.txt 改成 arr1.txt:
sendAjax('./data/arr1.txt', function (data) {
console.log('成功了')
console.log(data)
sendAjax('./data/json.txt', function (data) {
console.log('成功了')
console.log(data)
}, function () {
// console.log('失败了')
})
}, function () {
// console.log('失败了')
})
控制台:
下面我们不讨论出错的情况,假设我们所有的请求都一定会成功,可是像上面那种请求方式,也未免太麻烦,关键是可读性很差。试想,上面只有两个请求,如果有十个、二十个请求呢?岂不是要疯狂的层层嵌套?这就变成了大家所说的“回调地狱”。
“回调地狱”的问题先放在这。
我们来看看 jQuery 是怎么玩的,请自行引入 jQuery。
$.ajax({
url: './data/arr.txt',
dataType: 'json',
success: function (data) {
console.log('成功了')
console.log(data)
},
error: function (err) {
console.log('失败了')
console.log(err)
}
})
$.ajax({
url: './data/json.txt',
dataType: 'json',
success: function (data) {
console.log('成功了')
console.log(data)
},
error: function (err) {
console.log('失败了')
console.log(err)
}
})
同样的,来个封装:
function sendAjax(url, success, error) {
$.ajax({
url: url,
dataType: 'json',
success,
error,
})
}
sendAjax('./data/arr.txt', function (data) {
console.log('成功了')
console.log(data)
}, function (err) {
console.log('失败了')
console.log(err)
})
sendAjax('./data/json.txt', function (data) {
console.log('成功了')
console.log(data)
}, function (err) {
console.log('失败了')
console.log(err)
})
控制台:
如果有同样的需求,即 必须请求 arr.txt 成功后,才能请求 json.txt:
sendAjax('./data/arr.txt', function (data) {
console.log('成功了')
console.log(data)
sendAjax('./data/json.txt', function (data) {
console.log('成功了')
console.log(data)
}, function (err) {
console.log('失败了')
console.log(err)
})
}, function (err) {
console.log('失败了')
console.log(err)
})
可以看出,jQuery 同样存在“回调地狱”的问题。
二、用 Promise 发送请求
为了解决上述问题,Promise 就出现了。
Promise 可以使得你的异步代码,写起来就像同步代码,也就是说,你可以不用再层层嵌套。从而也提高了代码的可读性。
对于 Promise,有几个重点必须知道:
Promise 是一个构造函数
它接收一个回调函数作为参数
回调函数中又可以接收两个参数(这两个参数也是函数)
它返回一个 Promise 实例对象
实例对象有 then 方法
let p = new Promise(function (resolve, reject) {
if (成功) {
resolve() // 如果成功,就执行 resolve
} else {
reject() // 如果失败,就执行 reject
}
})
p.then(function () {}, function () {}) // 前面的 function 对应上面的 resolve,后面的 function 对应上面的 reject
现在,我们使用 Promise 重构上面的原生 ajax 代码:
function sendAjax(url) {
let xhr = new XMLHttpRequest()
return new Promise(function (resolve, reject) {
xhr.open('GET', url)
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
resolve(xhr.responseText) // 成功执行 resolve
} else {
reject() // 失败执行 reject
}
}
}
xhr.send()
})
}
let p1 = sendAjax('./data/arr.txt')
p1.then(function (data) {
console.log('成功了')
console.log(data)
}, function () {
console.log('失败了')
})
let p2 = sendAjax('./data/json.txt')
p2.then(function (data) {
console.log('成功了')
console.log(data)
}, function () {
console.log('失败了')
})
再想想那个需求:必须请求 arr.txt 成功后,才能请求 json.txt:
let p1 = sendAjax('./data/arr.txt')
p1.then(function (data) {
console.log('成功了')
console.log(data)
let p2 = sendAjax('./data/json.txt')
p2.then(function (data) {
console.log('成功了')
console.log(data)
}, function () {
console.log('失败了')
})
}, function () {
console.log('失败了')
})
这看起来似乎并没有解决“回调地狱”的问题!
这是因为我们的 Promise 没用到点子上。
我们要使用 Promise 中的 all 方法:
Promise.all 方法接收一个数组作为参数;
Promise.all 方法返回一个 Promise 实例(且称为实例对象 p );
只有当数组内所有的 promise 都成功,p 才执行成功(resolve)的回调函数;
如果数组内有一个 promise 失败,p 就执行失败(reject)的回调函数。
function createPromise(url) {
let xhr = new XMLHttpRequest()
return new Promise(function (resolve, reject) {
xhr.open('GET', url)
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
resolve(xhr.responseText)
} else {
reject()
}
}
}
xhr.send()
})
}
Promise.all([
createPromise('./data/arr.txt'), // 现在这里看起来就像是同步代码了
createPromise('./data/json.txt')
]).then((data) => {
console.log('成功了')
console.log(data)
}, () => {
console.log('至少有一个失败了')
})
至此,异步代码被写成了同步代码,“回调地狱”不见了。
那么,jQuery 它支持 Promise 吗?
答案是肯定的,不过你得使用高版本的 jQuery。
// 我这里用的是 3.xxx 的版本
<script ></script>
使用 jQuery 改写上面原生的代码:
Promise.all([
$.ajax({url: './data/arr.txt', dataType: 'json'}), // jQuery 的 ajax 方法直接返回一个 Promise 实例
$.ajax({url: './data/json.txt', dataType: 'json'}),
]).then((data) => {
console.log('成功了')
console.log(data)
}, (err) => {
console.log('失败了')
console.log(err)
})
控制台:
了解了 all 方法,再来看一看 race 方法。
Promise.race 方法用法与 Promise.all 方法类似,不同在于:
(这一段总感觉说的不严谨,哪位小伙伴给开导开导呗[滑稽])
如果成功,all 将所有成功的值放到数组中并返回(多个值),race 返回最先成功的那个值(一个值);
如果失败,all 和 race 都返回最先失败的值;
如果既有成功又有失败,all 仍然返回失败的值,race 返回失败的值,同时还返回成功的值,如:
Promise.race([ // 使用 race 方法
$.ajax({url: './data/arr.txt', dataType: 'json'}),
$.ajax({url: './data/json1.txt', dataType: 'json'}), // 这里把 json.txt 改成了 json1.txt
]).then((data) => {
console.log('成功了')
console.log(data)
}, (err) => {
console.log('失败了')
console.log(err)
})
控制台:
END~~
版权声明: 本文章来自知乎专栏《小谷悠悠伴我行》BarryDong 的知乎文章,可点击文末的阅读原文查看。如需转载,务必先与我们联系。
以上是关于Ajax VS Promise|精选博客的主要内容,如果未能解决你的问题,请参考以下文章
VSCode自定义代码片段12——JavaScript的Promise对象
VSCode自定义代码片段12——JavaScript的Promise对象