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()
Ajax VS Promise|精选博客
Ajax VS Promise|精选博客

换句话说,你应该安装一个 http-server 工具:

npm install http-server  // 安装

http-server . -c-1 // 使用

然后根据提示,打开 url 即可。

现在,浏览器控制台中可以看到:

Ajax VS Promise|精选博客

但是上面的 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 VS Promise|精选博客

这样,我们发送 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('失败了')
})

控制台:

Ajax VS Promise|精选博客

下面我们不讨论出错的情况,假设我们所有的请求都一定会成功,可是像上面那种请求方式,也未免太麻烦,关键是可读性很差。试想,上面只有两个请求,如果有十个、二十个请求呢?岂不是要疯狂的层层嵌套?这就变成了大家所说的“回调地狱”。

Ajax VS Promise|精选博客
图片来源于网络

“回调地狱”的问题先放在这。

我们来看看 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)
})

控制台:

Ajax VS Promise|精选博客

如果有同样的需求,即 必须请求 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)
})

控制台:

Ajax VS Promise|精选博客

了解了 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对象

框架基础:ajax设计方案--- 集成promise规范,更优雅的书写代码

(转)博客园登陆__JSEncrypt 分析

vs 2010代码片段

vs 2010代码片段