JavaScript 同步和异步

731 阅读2分钟

同步和异步

异步和单线程

异步又是js一个非常重要的内容,js三座大山:原型和原型链,作用域和闭包,异步和单线程

  我们已经跨过了两座大山,再跨第三座大山,你的js基础知识至少在语法层面已经达到入门的阶段,不能说很扎实,也不能说很全面,扎实和全面还是要看自己的学习程度和应用程度。

js是单线程语言,只能同时做一件事

浏览器和 nodejs 已支持js启动进程,如web Worker

js 和 DOM渲染共同一个线程,因为js可修改DOM结构

遇到等待(网络请求,定时任务)不能卡住

需要异步

异步就是为了解决单线程等待的问题

异步是基于 callback 函数形式来调用的

同步和异步的区别是什么?

  这个问题看似问和没问一样,但是我觉得这里面还是很能表达出对异步理解的问题,特别是对于js刚入门的同学,你可能知道异步是用来干什么的,也知道异步怎么用。到底为什么会有异步,异步和同步有什么区别,为什么不能直接用同步?对于这种问题深入一下你可能就蒙了

1. 基于js是单线程语言

2. 异步不会阻塞代码执行

3. 同步会阻塞代码执行

Promise

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

const url1 = "./data1.json"
const url2 = "./data2.json"
const url3 = "./data3.json"
getData(url1).then(data1 => {
    console.log(data1)
    return getData(url2)
}).then(data2 => {
    console.log(data2)
    return getData(url3)
}).then(data3 => {
    console.log(data3)
}).catch(err => console.error(err))

then就是new Promise里面的方法,data1就是我们通过url1获取的数据,然后直接return getData(url2) 然后可以接着.then。最后点catch

Promise把callback嵌套的形式变成了一个非嵌套的形式,变成了管道串联的形式。

Promise里面需要传递一个函数,函数里面有两个参数 resolve和reject,当success成功的时候执行resolve,用resolve把data返回回去,失败的时候执行error。当触发了resolve和触发了reject的时候,同理会触发then或者catch

手写 Promise 加载一张图片

// 案例一 执行一个url
function loadImg(src) {
    return new Promise(
        (resolve, reject) => {
            // resolve,reject 也是函数
            const img = document.createElement("img")
            img.onload = () => {
                resolve(img)
            }
            img.onerror = () => {
                const err = new Error(`图片加载失败! ${src}`)
                reject(err)
            }
            img.src = src
        }
    )
}

const url = "http://t8.baidu.com/it/u=2247852322,986532796&fm=79&app=86&f=JPEG?w=1280&h=853"

loadImg(url).then(img => {
    console.log(img.width)
    return img
}).then(img => {
    console.log(img.height)
}).catch(err => console.log(err))
// 案例二 执行两个url
function loadImg(src) {
    return new Promise(
        (resolve, reject) => {
            // resolve,reject 也是函数
            const img = document.createElement("img")
            img.onload = () => {
                resolve(img)
            }
            img.onerror = () => {
                const err = new Error(`图片加载失败! ${src}`)
                reject(err)
            }
            img.src = src
        }
    )
}

const url1 = "http://t8.baidu.com/it/u=2247852322,986532796&fm=79&app=86&f=JPEG?w=1280&h=853"
const url2 = "http://t9.baidu.com/it/u=583874135,70653437&fm=79&app=86&f=JPEG?w=3607&h=2408"

loadImg(url1).then(img1 => {
    console.log(img1.width)
    return img1
}).then(img1 => {
    console.log(img1.height)
    return loadImg(url2) // return promise 实例
}).then(img2 => {
    console.log(img2.width)
    return img2
}).then(img2 => {
    console.log(img2.height)
}).catch(err => console.log(err))

提示:千万不要忘记return

前端使用异步的场景有哪些?

1. 网络请求,如ajax图片加载

2. 定时任务,如setTimeout