同步与异步
同步就是能直接拿到结果,比如在医院挂号室,拿到号才能离开窗口。
异步就是不能直接拿到结果,比如在餐厅等餐时还可以去逛街。你可以每10分钟去餐厅问一下(轮询),你也可以扫码用微信接收通知(回调)
回调
异步与回调的关系:
异步任务需要在得到结果时通知JS来拿结果
怎么通知呢?
可以让JS留一个函数地址(电话号码)给浏览器
异步任务完成时浏览器调用该函数地址即可(拨打电话)
同时把结果作为参数传给该函数(电话里说可以来吃了)
这个函数是我写给浏览器调用的,所以是回调函数
注意:
异步不一定只用回调可以用轮询,回调不一定只在异步任务里面,也可以在同步任务里面。
function f1() {
console.log("我是回调")
}
function f2(fn) {
console.log("我是函数不是回调")
fn()
}
f2(f1)
上面的f1没有被调用,但是f1传给了f2 ,f2调用了f1。f1就是写给f2调用的函数。那么f1就是回调。
判断同步与异步(初级)
如果一个函数的返回值处于以下几个内部那么就是异步函数:
setTimeout()
AJAX
AddEventListener()
绝对不能让AJAX改成同步的。
function rollTheDice(fn) {
setTimeout(() => {
fn(parseInt(Math.random() * 6) + 1)
}, 1000) // 随机返回1到6的数字
}
rollTheDice((x) => {
console.log(x)
})
方法一:回调接受2个参数
fs.readFile('./text',(error ,data)=>{
if(error){ console.log('失败');return}
console.log(data.toString())
})
方法二:用2个回调
ajax('get','/1.json',data=>{},error=>{})
ajax('get','/1.json',{
success:()=>{}.fail:()=>{}
})
回调的问题
- 不够规范,名称五花八门
- 容易出现回调地狱,回调地狱就是我们异步任务中嵌套异步任务一层一层的,导致我们的代码臃肿,而promise链式调用解决这种代码问题。
- 很难出现错误处理
getUser((user) => {
getGroups(user, (groups) => {
groups.forEach((g) => {
g.filter((x) => x.ownerId === user.Id).forEach((x) =>
console.log(x)
)
})
})
})
Promise
Promise 对象是由关键字 new 及其构造函数来创建的。该构造函数会把一个叫做“处理器函数”(executor function)的函数作为它的参数。这个“处理器函数”接受两个函数——resolve 和 reject ——作为其参数。当异步任务顺利完成且返回结果值时,会调用 resolve 函数;而当异步任务失败且返回失败原因(通常是一个错误对象)时,会调用reject 函数。
return new Promsie((resolve,reject)=>{...})
实例
let myFirstPromise = new Promise(function(resolve, reject){
//当异步代码执行成功时,我们才会调用resolve(...), 当异步代码失败时就会调用reject(...)
//在本例中,我们使用setTimeout(...)来模拟异步代码,实际编码时可能是XHR请求或是HTML5的一些API方法.
setTimeout(function(){
resolve("成功!"); //代码正常执行!
}, 250);
});
myFirstPromise.then(function(successMessage){
//successMessage的值是上面调用resolve(...)方法传入的值.
//successMessage参数不一定非要是字符串类型,这里只是举个例子
console.log("Yay! " + successMessage);
});
return new Promise((resolve,rejec)=>{...})- 任务成功则调用
resolve(result) - 任务失败则调用
reject(error) resolve和reject会再去调用成功和失败函数- 使用
.then(success, fail)传入成功和失败函数
ajax = (method, url, options) => {
return new Promise((resolve, reject) => {
const { success, fail } = options
const request27 = newXMLHttpRequest()
request.open(method, url)
request.onreadystatechange = () => {
if (request.readyState === 4) {
//成功就调用resolve, 失败就调用reject
if (request.status < 400) {
resolve.call(null, request.response)
} else if (request.status >= 400) {
reject.call(null, request)
}
}
}
request.send()
})
}
但是封装的JAXA不能POST ;不能添加状态码
你对 Promise 的了解?
-
Promise 不是前端发明的
-
Promise 是目前前端解决异步问题的统一方案
-
window.Promise 是一个全局函数,可以用来构造 Promise 对象
-
使用 return new Promise((resolve, reject)=> {}) 就可以构造一个 Promise 对象
-
构造出来的 Promise 对象含有一个 .then() 函数属性
.then() 与.catch()
.then()
- then方法提供一个供自定义的回调函数,若传入非函数,则会忽略当前then方法。
- 回调函数中会把上一个then中返回的值当做参数值供当前then方法调用。
- then方法执行完毕后需要返回一个新的值给下一个then调用(没有返回值默认使用undefined)。
- 每个then只可能使用前一个then的返回值。
.catch()
在执行resolve的回调(也就是上面then中的第一个参数)时,如果抛出异常了(代码出错了),那么并不会报错卡死js,而是会进到这个catch方法中。
也就是说当函数里面出现错误是 JS不会停止运行,而是将错误传给.catch()。然后继续执行口面的回调。
function getNumber() {
var p = new Promise(function (resolve, reject) {
//做一些异步操作
setTimeout(function () {
var num = Math.ceil(Math.random() * 10) //生成1-10的随机数
if (num <= 5) {
resolve(num)
} else {
reject("数字太大了")
}
}, 1000)
})
return p
}
getNumber()
.then((data) => {
console.log("成功了")
console.log(data)
})
.catch((data) => {
console.log("失败了,错误传过来,继续执行")
console.log(data)
})
.then(() => {
console.log("绕开了,继续执行")
})
由此可见:Promise最大的好处是在异步执行的流程中,把执行代码和处理结果的代码清晰地分离了。
jQuery.ajax
type
类型: String
请求方式 ("POST" 或 "GET"), 默认为 "GET"。注意:其它 HTTP 请求方法,如 PUT 和 DELETE 也可以使用,但仅部分浏览器支持。
url
类型: String
发送请求的地址 (默认: 当前页面地址)。
username
类型: String
于响应HTTP访问认证请求的用户名
// 发出请求后立即分配处理程序,
// 并记住此请求的jqxhr对象
var jqxhr = $.ajax( "example.php" )
.done(function() { alert("success"); })
.fail(function() { alert("error"); })
.always(function() { alert("complete"); });
// perform other work here ...
// 为上述请求设置另一个完成功能
jqxhr.always(function() { alert("second complete"); });
axios
Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。
执行 GET 请求
// 为给定 ID 的 user 创建请求
axios.get('/user?ID=12345')
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
// 上面的请求也可以这样做
axios.get('/user', {
params: {
ID: 12345
}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
执行 POST 请求
axios.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone'
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
执行多个并发请求
function getUserAccount() {
return axios.get('/user/12345');
}
function getUserPermissions() {
return axios.get('/user/12345/permissions');
}
axios.all([getUserAccount(), getUserPermissions()])
.then(axios.spread(function (acct, perms) {
// 两个请求现在都执行完成
}));
资料来源:饥人谷
本文为贰贰的原创文章,著作权归本人和饥人谷所有,转载务必注明来源