ajax
最早为了实现局部请求无刷新,有了ajax的概念。在原生js是时代,请求数据都需要自己手写一个ajax。现在还有很多面试题会让手写一个ajax
// 先实例化一个XMLHttpRequest对象
const xhr = new XMLHttpRequest()
// xhr 具有一个 open 方法,相当于填写配置先初始化。这时候没有发出请求
// method: 请求方式 —— get / post
// url:请求的地址
// async:是否异步请求,默认为 true(异步)
xhr.open(method, url, async)
// send 方法发送请求,并接受一个可选参数
// 当请求方式为 post 时,可以将请求体的参数传入
// 当请求方式为 get 时,可以不传或传入 null
xhr.send(data)
// xhr上有一个readyStatus值。他会随着请求的阶段不同而变化:
// xhr.readyStatus==0 尚未调用 open 方法
// xhr.readyStatus==1 已调用 open 但还未发送请求(未调用 send)
// xhr.readyStatus==2 已发送请求(已调用 send)
// xhr.readyStatus==3 已接收到请求返回的数据
// xhr.readyStatus==4 请求已完成
// 当readyStatus变化时都会执行onreadystatechange 回调。
// responseText: 请求返回的数据内容
// status: 响应的HTTP状态,如 200 304 404 等
xhr.onreadystatechange = () => {
if (xhr.readyStatus === 4) {
if (xhr.status >= 200 &&
xhr.status < 300 ||
xhr.status == 304) {
console.log('请求成功', xhr.responseText)
}
}
}
// 设置超时时间为1000毫秒
xhr.timeout = 1000
jquery
后来在jquery盛行的时代。将ajax封装成了一个函数。可以直接调用
$.ajax({
type : "POST",
url:'http://aaaa.com',
async:true,
dataType:'json',
data:{a:'aa'},
success :function(msg){
//请求成功函数
},
error:function(err){
//请求失败函数
}
});
jquery1.5之后
var ajax = $.ajax('data.json')
ajax.done(function () {
console.log('success 1')
})
.fail(function () {
console.log('error')
})
.done(function () {
console.log('success 2')
})
console.log(ajax) // 返回一个 deferred 对象
区别:
之前返回的是一个XHR对象,这个对象不可能有done或者fail的方法的
1.5开始返回一个deferred对象,这个对象就带有done和fail的方法,并且是等着请求返回之后再去调用
promise前身
// 改造前
var wait = function() {
var task = function () {
console.log('ok')
}
setTimeout(task, 2000)
}
wait()
// 改造后
function waitHandle() {
var dtd = $.Deferred()
var wait = function(dtd) {
var task = function() {
console.log('ok');
dtd.resolve()
// dtd.reject()
}
setTimeout(task, 2000)
return dtd.promise() // 返回promise对象,使用时不可以修改状态。promise的前身
}
return wait(dtd);
}
waitHandle().then();
1.5改造之后最大的好处就是可以通过then的方法来链式调用。不再会有回调地狱。而且状态一旦改变,也不能再变成其他状态了。和之后的promise一样。
promise
es6中将之前社区中的方案正式纳入标准,制定了promise/A+规范。也就可以直接的使用promise
const getJSON = function(url) {
const promise = new Promise(function(resolve, reject){
const handler = function() {
if (this.readyState !== 4) {
return;
}
if (this.status === 200) {
resolve(this.response);
} else {
reject(new Error(this.statusText));
}
};
const client = new XMLHttpRequest();
client.open("GET", url);
client.onreadystatechange = handler;
client.responseType = "json";
client.setRequestHeader("Accept", "application/json");
client.send();
});
return promise;
};
getJSON("/posts.json").then(function(json) {
console.log('Contents: ' + json);
}, function(error) {
console.error('出错了', error);
});
generator
promise的出现只是回调函数的改进,使用then方法以后,异步任务的两段执行看得更清楚了,会造成代码冗余。一堆的then。如下
var readFile = require('fs-readfile-promise');
readFile(fileA)
.then(function (data) {
console.log(data.toString());
})
.then(function () {
return readFile(fileB);
})
.then(function (data) {
console.log(data.toString());
})
.catch(function (err) {
console.log(err);
});
于是有了更好的解决方案---generator
var fetch = require('node-fetch');
function* gen(){
var url = 'https://api.github.com/users/github';
var result = yield fetch(url);
console.log(result.bio);
}
var g = gen();
var result = g.next();
result.value.then(function(data){
return data.json();
}).then(function(data){
g.next(data);
});
Generator 函数可以暂停执行和恢复执行,这是它能封装异步任务的根本原因。虽然 Generator 函数将异步操作表示得很简洁,但是流程管理却不方便,需要执行器`控制他什么时候执行第一步,什么时候执行第二步。并且传递参数。
于是有了co
这种流程管理库。
简单的流程管理如下。会一直执行下去。
function* gen() {
// ...
}
var g = gen();
var res = g.next();
while(!res.done){
console.log(res.value);
res = g.next();
}
async await --终极方案
async function getStockPriceByName(name) {
const symbol = await getStockSymbol(name);
const stockPrice = await getStockPrice(symbol);
return stockPrice;
}
getStockPriceByName('goog').then(function (result) {
console.log(result);
});
好处
(1)内置执行器。
Generator 函数的执行必须靠执行器,所以才有了co模块,而async函数自带执行器。也就是说,async函数的执行,与普通函数一模一样,只要一行。
getStockPriceByName();
上面的代码调用了getStockPriceByName函数,然后它就会自动执行,输出最后结果。这完全不像 Generator 函数,需要调用next方法,或者用co模块,才能真正执行,得到最后结果。
(2)更好的语义。
async和await,比起星号和yield,语义更清楚了。async表示函数里有异步操作,await表示紧跟在后面的表达式需要等待结果。
(3)更广的适用性。
co模块约定,yield命令后面只能是 Thunk 函数或 Promise 对象,而async函数的await命令后面,可以是 Promise 对象和原始类型的值(数值、字符串和布尔值,但这时会自动转成立即 resolved 的 Promise 对象)。
(4)返回值是 Promise。
async函数的返回值是 Promise 对象,这比 Generator 函数的返回值是 Iterator 对象方便多了。你可以用then方法指定下一步的操作。
进一步说,async函数完全可以看作多个异步操作,包装成的一个 Promise 对象,而await命令就是内部then命令的语法糖。
在nodejs中已经使用async 、 await做为异步操作的解决方案
网友评论