基础知识点复习之异步

223 阅读2分钟

在工作和面试中,基础知识必须牢固,今天开始,不仅要继续读源码类知识,还要复习基础知识。

1. 什么是单线程,和异步有什么关系?

1.1 单线程

单线程 - 只有一个线程,同一时间只能做一件事。

console.log(100)
setTimeout(() => {
    console.log(200)
}, 1000)
console.log(300)
console.log(400)

1.2 原因

原因 - 避免DOM渲染的冲突。

详细解释:浏览器需要修改DOM,JS可以修改DOM,JS执行的时候,浏览器DOM渲染会暂停。两段JS也不能同时执行,都修改DOM就冲突了。

webworker支持多线程,但是不能访问DOM。

1.3 异步

解决方案 - 异步。

问题一:没按照书写方式执行,可读性差。

问题二:callback不容易模块化。(后期维护代码不好排查问题)

1.4 解答

单线程就是同时只做一件事,两段JS代码不能同时执行。

原因就是为了避免DOM渲染的冲突。

异步是单线程的解决方案,但是也存在相应的问题。

2. 什么是event-loop?

事件轮询,JS实现异步的具体解决方案。

同步代码,直接执行。

异步函数先放在异步队列中。

待同步函数执行完毕,轮询执行异步队列的函数。

涉及到宏任务和微任务的知识,可以参考网上的博客。

3. jquery的Deferred

var ajax = $.ajax('data.json')
ajax.then(function () {
    // 成功
}, function () {
    // 失败
})
.then(function () {
    // 成功
}, function () {
    // 失败
})

// 或者
ajax.done(function () {
    console.log('success')
}).fail(function () {
    console.log('fail')
}).done(function () {
    console.log('success2')
}).done(function () {
    console.log('success3')
})

使用jQuery Deferred

function handleWait () {
    var dtd = $.Deferred() // 创建Deferred实例

    var wait = function (dtd) {
        var task = function () {
            console.log('执行完成')
            dtd.resolve() // 成功
            // dtd.reject() // 失败
        }

        setTimeout(task, 1000)
        return dtd.promise() // 加promise的原因是防止外面修改resolve或者reject状态
    }


    return wait(dtd)
}

// 返回的promise对象后需要$.when处理一下
var result = handleWait()
$.when(result).then(function () {
    console.log('success 1')
}, function () {
    console.log('error 1')
})

// 但是reject的时候,不能写成链式操作,需要拆开写
$.when(result).then(function () {
    console.log('success 1')
}, function () {
    console.log('error 1')
})
$.when(result).then(function () {
    console.log('success 2')
}, function () {
    console.log('error 2')
})

4. Promise的基本使用和原理

4.1 基本语法

基本语法在ES6中已经介绍过,这里就忽略了。

4.2 异常捕获

无论有多少个then,统一用catch捕获异常

result.then(function () {
    // 成功
}).then(function () {
    // 成功
}).catch(function (err) {
    // 捕获异常
})

4.3 多个串联

可以通过第一个then返回一个promise对象,实行串联。

function loadText (src) {
    return new Promise((resolve, reject) => {
        $.ajax({
            url: src,
            success: function (data) {
                resolve(data)
            },
            fail: function (err) {
                reject(err)
            }
        })
    })
}

var src1 = './data.txt'
var result1 = loadText(src1)
var src2 = './data2.txt'
var result2 = loadText(src2)

result1.then(function (data) {
    console.log('data1' + data)
    return result2
}).then(function (data) {
    console.log('data2' + data)
})

4.4 Promise.all Promise.race

Promise.all接受一个promise对象数组,待全部完成后统一执行then中的success,then中接受的参数是一个数组,里面是所有的返回内容

Promise.all([result1, result2]).then((datas) => {
    console.log(datas)
})

Promise.race接受一个promise对象数组,只要有一个完成就执行then中的success,then中接受的参数是最先返回的内容

Promise.race([result1, result2]).then((data) => {
    console.log(data)
})

4.5 Promise状态

初始状态: pending

成功:fulfilled

失败:rejected

5. 介绍一下async/await(和Promise的区别、联系)

async/await是最直接的同步写法

5.1 基本语法

function loadText (src) {
    return new Promise((resolve, reject) => {
        $.ajax({
            url: src,
            success: function (data) {
                resolve(data)
            },
            error: function (err) {
               
                reject(err)
            }
        })
    })
}

async function handleLoadText () {
    let result1 = await loadText('./data.txt')
    console.log(result1)
    let result2 = await loadText('./data2.txt')
    console.log(result2)
}

handleLoadText()

5.2 解答

使用了Promise,并没有和Promise冲突

完全是同步的写法,再也没有回调函数

6. 总结当前JS解决异步的方案

jquery Deferred

promise

async await

generator