js中的异步

402 阅读2分钟

同步与异步

同步,即为等待结果的操作。

// 同步的sleep
function sleep(seconds) {
    var start = new Date()
    while(new Date() - start < seconds * 1000){}
    return
}
// 如下操作在打印出1之后,会等待3秒,然后打印出‘wakeup’,后再打印出2
console.log(1)           // 打印出1
sleep(3)                 // 休眠3秒
console.log('wake up')   // 唤醒
console.log(2)           // 打印出2
drawing

异步,即为不等待结果的操作。

function sleep(seconds, fn) {
    setTimeout(fn, seconds * 1000)
}
// 如下操作,打印出1后,会直接打印出2,在三秒之后会打印出‘wakeup’,打印2的操作不会等3秒之后再出现。
// js在打印完1后,告诉浏览器3秒之后打印‘wake up’,js则继续进行接下来的操作,等到3秒后,浏览器会打印出‘wake up’
console.log(1)                        
sleep(3, ()=>console.log('wake up'))
console.log(2)    

前端经常遇到的异步

// 第一次访问的时候没有缓存需要异步下载请求得到图片,第二次访问的时候可以从缓存中读取图片
document.getElementsByTagName('img')[0].width;  // 宽度为0
console.log('done')

document.getElementsByTagNames('img')[0].onload = function(){
    console.log(this.width) // 宽度不为 0
    console.log('real done')
}
console.log('done')

面试中的异步

let liList = document.querySelectorAll('li')
for(var i=0; i<liList.length; i++){
    liList[i].onclick = function(){
        console.log(i)    //  不管点击哪个,显示的都是6
    }
}

// 将循环中的var改成let,则可以点击显示对应的li的下标
// let不会提升作用域,所以每次循环都有一个新的i

Ajax中的异步

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

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

异步的形式

轮询

拿到结果后放到某个地方,定期去看这个地方有没有结果。

function buyFruit() {
    setTimeout(()=>{
        window.apple = "买到的苹果";
    }, Math.Random()*10*1000)
}
buyFruit() 
var id = setInterval(()=>{
    if(window.apple){
        console.log(window.apple);
        window.clearInterval(id)
    }else{
        console.log("桌子上没有水果");
    }
}, 1000)

回调

有了结果后,通知我。

function buyFruit() {
    setTimeout((fn)=>{
        fn.call(undefined, "买到的苹果");
    }, Math.Random()*10*1000)
}
buyFruit(function(){
    console.log(arguments[0])
})

回调的形式

Node.jserror-list形式

fs.readFile('./1.txt', (error, content)=>{
     if(error){
         // 失败
     }else{
         // 成功
     }
 })

jQuerysuccess/error形式

$.ajax({
     url:'/xxx',
     success:()=>{},
     error: ()=>{}
 })

jQuerydone/fail/always形式

柯里化函数

$.ajax({
     url:'/xxx',
 }).done( ()=>{} ).fail( ()=>{} ).always( ()=> {})

Promisethen形式

$.ajax({
     url:'/xxx',
 }).then( ()=>{}, ()=>{} ).then( ()=>{})   
// 前面成功return的值可以传给后面的then里面的值

Promise A+规范

axios({
    url: 'xxx'
}).then(s1,e1)   // 第一责任人
    .then(s2, e2)  // 第二责任人
    .then(s3, e3)  // 第三责任人

axios成功,则s1一定会被调用到; 在s1e1没有报错的情况下,会调用s2; 在s1e1报错的情况下,会调用e2

axios({
    url: '',
    async: true
}).then((x)=>{
    console.log('成功')
    return Promise.reject('reject11111')
}, (y)=>{
    console.log('失败')
}).then((x)=>{
    console.log('成功2')
}, (y)=>{
    console.log('失败2')
    console.log(y)
})

// 输出结果 成功  失败2  reject11111

如何处理异常??? 出现异常会调用下一个thenerror函数 若没有下一个thenerror,则错误会抛给开发者,或者写catch函数(相当于一个失败函数)

axios({
    url: '',
    async: true
}).then((x)=>{
    console.log('成功')
    return Promise.reject('reject11111')
}, (y)=>{
    console.log('失败')
}).then((x)=>{
    console.log('成功2')
}).catch((x)=>{
    console.log('catch')
    console.log(x)
})

// 输出结果 成功  catch  reject11111

catch等价于then(undefined, ()=>{}), 相当于一个没有成功函数只有失败函数的then

自己写Promise

buyFruit(){
    return new Promise((x, y)=>{
        setTimeout(()=>{
            x('apple')
        }, 1000)
    })
}

var promise = buyFruit()
promise.then(()=>{console.log(1)}, ()=>{console.log(2)})
function buyFruit(){
    return new Promise((resolve, reject)=>{
        setTimeout(()=>{
            resolve('apple')
        }, 10000)
    })
}

var promise = buyFruit()
promise.then(()=>{console.log(1)}, ()=>{console.log(2)})