![84c8f61a4416f21e5363d5aa5744994d.png](https://i-blog.csdnimg.cn/blog_migrate/077491f01ede0736db2099a70b5e4cfe.jpeg)
同步与异步
同步:等待结果
异步:不等待结果
注意,异步常常伴随回调一起出现,但是异步不是回调,回调也不一定是异步。
[回调是拿到异步结果的一种方式,回调也可以拿到同步结果]
// 同步的 sleep
function sleep(seconds){
var start = new Date()
while(new Date() - start < seconds * 1000){
}
return
}
console.log(1)
sleep(3)
console.log('wake up')
console.log(2)
![f769366ac91a99edb9b9d37c8c060292.png](https://i-blog.csdnimg.cn/blog_migrate/bbdaf0a83d44628c8f6808fa72aabaf7.jpeg)
从黄色区域可以看到3s的时间js一直在等待,
这里同步过程:打印1,定3s的闹钟并开始计时,3s到了打印wake up,接着打印2
//异步的 sleep
function sleep(seconds, fn){
setTimeout(fn, seconds * 1000)
}
console.log(1)
sleep(3, ()=> console.log('wake up'))
console.log(2)
![aee0a1300853daf45f6a5ccc28e3c65f.png](https://i-blog.csdnimg.cn/blog_migrate/fda48c387b1524cddaf48db77e680f59.jpeg)
用了异步之后,js空闲了很多,在空闲的这段时间,实际上是浏览器的计时器在工作,
这里异步执行过程:打印1,定一个3s的闹钟并开始计时,直接打印2,3s到了打印 wake up
异步是不可预测的,一般是添加计时器模拟或者通过监听事件来满足需求
异步实例1: 图片加载是需要时间的,
假设图片宽度300px
w = document.getElementsByTagNames('img')[0].width // 宽度为 0
这是因为从服务器请求图片是一个异步过程,还没有拿到图片就获取宽度默认为0
时序图:
![efbfc4c512565783826edc4cbb783f3a.png](https://i-blog.csdnimg.cn/blog_migrate/fbb820cba95128eaae1c402111877a86.jpeg)
解决:图片加载完后会触发onload事件
let img = document.getElementsByTagNames('img')[0];
img.onload = function(){
console.log(img.width) //300
}
异步实例2:
假设有3个li,想要的结果:点击li打印对应索引
let liList = document.querySelectorAll('li')
for(var i=0; i<liList.length; i++){
liList[i].onclick = function(){
console.log(i)
}
}
结果是每次都打印3;i是全局的。
时序图:
![ca9fb30f9802fd54e96407a1777ccb4f.png](https://i-blog.csdnimg.cn/blog_migrate/d22d4c26c5f72f1580435d19fe4413ee.jpeg)
解决:用let
let liList = document.querySelectorAll('li')
for(let i=0; i<liList.length; i++){
liList[i].onclick = function(){
console.log(i)
}
}
时序图:
![8053131d47d4aa606af827be74e1e05e.png](https://i-blog.csdnimg.cn/blog_migrate/e32826fe7a5633987cf5eab1401bca2a.jpeg)
异步实例3:ajax的同步和异步
同步ajax:
let request = $.ajax({
url: '.',
async: false
})
console.log(request.responseText)
时序图:【在等待的时间内浏览器什么都不能做】
![fedc0927aa1a7cd6bd73b4e54e7c506d.png](https://i-blog.csdnimg.cn/blog_migrate/6146a5890f44bf8ca24343400e1c0b32.jpeg)
异步:
$.ajax({
url: '.',
async: true,
success: function(responseText){
console.log(responseText)
}
})
console.log(1)
时序图:【无需等待,当下载完成浏览器会通知js响应文本】
![3336bcf54fc364ecf4bc89eacb8ecb13.png](https://i-blog.csdnimg.cn/blog_migrate/389e28fc3f9753b1595d6b4fae5bfc1b.jpeg)
获取异步结果的形式:
setTimeout模拟异步(假设需要5s):
1.轮询:每隔一段时间查看一次有没有获取到,使用setInterval,当拿到结果后砸掉闹钟。
function getText(fn){
setTimeout(()=>{
window.text = 'some text'
},5000)
}
getText();
let timer = setInterval(()=>{
if(window.text){
clearInterval(timer);
console.log(window.text)
}
},1000) //1s看一次
2.回调:拿到结果后直接执行回调,回调内处理结果。
function getText(fn){
setTimeout(()=>{
fn.call(undefined,'someText');
},5000)
}
getText(function(){
console.log(arguments[0])
})
回调的形式:
- Node.js 的 error-first 形式
fs.readFile('./1.txt', (error, content)=>{
if(error){
// 失败
}else{
// 成功
}
})
2.jQuery 的 success / error 形式
$.ajax({
url:'/xxx',
success:()=>{},
error: ()=>{}
})
3.jQuery 的 done / fail / always 形式
$.ajax({
url:'/xxx',
}).done( ()=>{} ).fail( ()=>{} ).always( ()=> {})
4.Prosmise 的 then 形式
$.ajax({
url:'/xxx',
}).then( ()=>{}, ()=>{} ).then( ()=>{})
如何处理异常?
1.如何使用多个 success 函数?
promise 处理:
// 假设有三次then处理
axios({
url:"xxx"
}).then(s1,e1)
.then(s2,e2)
.then(s3,e3)
// 注意:不是请求成功一次执行s1,s2,s3 失败也不是依次执行e1,e2,e3
// 这里是否执行 s 和 e 取决于是否处理成功或失败,无论是处理成功请求 还是 处理失败的请求!!!
// 第一次(s1)处理成功请求无异常,或者(e1)处理失败的请求无异常 就会执行 s2
// 第一次(s1)处理成功请求出现异常,或者(e1)处理失败的请求出现异常 就会执行 e2
// 第二次同理 :
// 第二次(s2)处理 s1 或者 e1 的结果无异常,就会执行 s3
// 第二次(s2)处理 s1 或者 e1 的结果出现异常,就会执行 e3
2.在有多个成功回调的情况下,如何处理异常?
主动失败 reject:直接扔给失败2
![f75024151a0fadf82962cc0d15dfb8ee.png](https://i-blog.csdnimg.cn/blog_migrate/e49c8ff149d5714afcf0a4685fc64bfb.jpeg)
catch捕获错误: 这是一个语法糖,等价于 then(undefined,(x)=>{})
![87ae0396a0d4fdd1dfcb77c45ab19266.png](https://i-blog.csdnimg.cn/blog_migrate/583b8cae8d070209471e4da8a5fbe1d7.jpeg)
自己返回 Promise
function ajax(){
return new Promise((resolve, reject)=>{
做事
如果成功就调用 resolve
如果失败就调用 reject
})
}
var promise = ajax()
promise.then(successFn, errorFn)
function buyFruit(){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve('apple')
},5000)
})
}
let promise = buyFruit();
promise.then((res)=>{
console.log(res)
},(err)=>{
console.log(err)
})
//apple
Promise 深入阅读:http://www.cnblogs.com/hustskyking/p/promise.html
Promise/A+ 规范:https://segmentfault.com/a/1190000002452115
async / await(es2017)
async表示函数里有异步操作,await表示紧跟在后面的表达式需要等待结果。
async函数的返回值是 Promise 对象, await命令后面,可以是 Promise 对象和原始类型的值(数值、字符串和布尔值,但这时等同于同步操作)
// 1.如果success,等待执行完后继续后面的代码
function buyFruit(){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve('apple')
},5000)
})
}
var promise = await buyFruit();
console.log(2)
//5s后打印2
//2.如果失败,报错
function buyFruit(){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
reject()
},5000)
})
}
var promise = await buyFruit();
console.log(2)
// 5s 后 Uncaught (in promise) undefined
// 3.处理错误使用 try catch
try{
var promise = await buyFruit();
console.log('正常')
}catch(err){
console.log('异常了')
}
async function fn(){
var result = await buyFruit()
return result
}
var r = await fn()
console.log(r)
promise测试题:
实现 Promise 的简化版,满足以下需求即可
function Promise(???){
???
return ???
}
var promise = new Promise(function(x,y){
setTimeout(()=>{
x(101)
}, 3000)
})
promise.then((z)=>{
console.log(z) // 101
})
答案:https://judes.me/tech/frontend/2017/03/12/a_simple_promise.html
end!