切面是异步还是同步操作‘_JavaScript 异步

84c8f61a4416f21e5363d5aa5744994d.png

同步与异步

同步:等待结果

异步:不等待结果

注意,异步常常伴随回调一起出现,但是异步不是回调,回调也不一定是异步。

[回调是拿到异步结果的一种方式,回调也可以拿到同步结果]

// 同步的 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

从黄色区域可以看到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

用了异步之后,js空闲了很多,在空闲的这段时间,实际上是浏览器的计时器在工作,

这里异步执行过程:打印1,定一个3s的闹钟并开始计时,直接打印2,3s到了打印 wake up

异步是不可预测的,一般是添加计时器模拟或者通过监听事件来满足需求

异步实例1: 图片加载是需要时间的,

假设图片宽度300px

w = document.getElementsByTagNames('img')[0].width // 宽度为 0

这是因为从服务器请求图片是一个异步过程,还没有拿到图片就获取宽度默认为0

时序图:

efbfc4c512565783826edc4cbb783f3a.png

解决:图片加载完后会触发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

解决:用let

let liList = document.querySelectorAll('li')
for(let i=0; i<liList.length; i++){
    liList[i].onclick = function(){
        console.log(i)
    }
}

时序图:

8053131d47d4aa606af827be74e1e05e.png

异步实例3:ajax的同步和异步

同步ajax:

let request = $.ajax({
  url: '.',
  async: false
})
console.log(request.responseText)

时序图:【在等待的时间内浏览器什么都不能做】

fedc0927aa1a7cd6bd73b4e54e7c506d.png

异步:

$.ajax({
    url: '.',
    async: true,
    success: function(responseText){
        console.log(responseText)
    }
}) 
console.log(1)   

时序图:【无需等待,当下载完成浏览器会通知js响应文本】

3336bcf54fc364ecf4bc89eacb8ecb13.png

获取异步结果的形式:

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])
})

回调的形式:

  1. 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

catch捕获错误: 这是一个语法糖,等价于 then(undefined,(x)=>{})

87ae0396a0d4fdd1dfcb77c45ab19266.png

自己返回 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!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值