欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JavaScript 异步

程序员文章站 2024-01-28 09:35:52
...

JS是单线程执行,避免DOM渲染冲突:

  • 浏览器需要渲染DOM;
  • JS可以修改DOM,修改时浏览器会暂停渲染;
  • 两段JS同时执行会发生冲突;
  • webworker支持多线程,但不能访问DOM。

同步:代码顺序执行,中间可能会阻塞

console.log(100)
alert(200)    // 同步执行,点确认前会阻塞
console.log(300)

异步:不考虑执行结果(或通过回调获取执行结果),调用立即返回;

使用异步的场景:在可能发生等待、且等待过程中不能阻塞(像alert一样):

  • setTimeoutsetInterval
  • ajax请求,动态<img>加载;
  • 事件绑定。

通过异步解决执行效率低仍存在问题:

  1. 可读性差(不是按顺序执行);
  2. callback不容易做模块化;
console.log(1)
setTimeout(function() {    
    console.log(2)
}, 0)
console.log(3)
setTimeout(function() {    
    console.log(4)
}, 1000)
console.log(5)
// 1, 3, 5, 2, 4

// $.get("https://www.baidu.com", function(data){console.log(data)})

Event-Loop(事件轮询):

  1. 顺序执行所有同步函数;
  2. 需要等待的异步函数(延时、AJAX)会在等待完成后再暂存在异步队列(单线程);
  3. 轮询异步队列,依次取出函数执行。
$.ajax({
    url: "xxx",
    success: function(result) {
        console.log("a")
    }
})
setTimeout(function() {
    console.log("b")
}, 100)
setTimeout(function() {
    console.log("c")
})
console.log("d")

// 执行顺序:dcab或dcab(取决于AJAX请求时长)

jQuery Deferred

1.5版本前的AJAX:

var ajax = $.ajax({
    url: "data.json",
    success: function() {
        // ...
    },
    error: function() {
        // ...
    }
})
console.log(ajax)       // XHR对象

1.5版本后的AJAX(类似Promise):

Deferred两类API:

  • dtd.resolvedtd.reject
  • dtd.thendtd.donedtd.fail
var ajax = $.ajax("data.json")
ajax.done(function() {
    // ...
}).fail(function() {
    // ...
}).done(function() {

})
console.log(ajax)       // deferred对象


var ajax = $.ajax("data.json")
ajax.then(function() {
    // ...
}, function() {
    // ...
}).then(function() {
    // ...
}, function() {
    // ...
})
var wait = function() {
    var task = function() {
        console.log("")
    }
    setTimeout(task, 2000)
}
wait()

// 可修改为:
function waitHandle() {
    var dtd = $.Deferred()
    var wait = function(dtd) {
        var task = function() {
            console.log("")
            dtd.resolve()       // 异步任务已完成
        }
        setTimeout(task, 2000)
        return dtd          // 返回dtd.promise(),则最后返回promise对象
    }
    return wait(dtd)        // 必须有返回值
}

var w = waitHandle()
w.then...

Promise

Callback Hell:难以阅读的异步函数

function loadImg(src, callback, fail) {
    var img = document.createElement("img")
    img.onload = function() {
        callback(img)
    }
    img.onerror = function() {
        fail()
    }
    img.src = src
}

var src = ""
loadImg(src, function(img) {
    console.log(img.width)
}, function() {
    console.log("failed")
})

Promise

三种状态(不可逆):

  • pending(初始状态)
  • fulfilled(执行成功回调)
  • rejected(执行失败回调)
function loadImg(src) {
    const promise = new Promise(function(resolve, reject) {
        var img = document.createElement("img")
        img.onload = function() {
            resolve(img)
        }
        img.onerror = function() {
            reject()
        }
        img.src = src
    })
    return promise
}
var src = ""
var result = loadImg(src)
result.then(function(img) {         // promise实例,必须实现then方法(成功和失败的回调),且返回的必须是
    console.log(img.width)
}, function() {
    console.log("failed")
})

result.then(function(img) {
    console.log(img.height)
})


// 异常捕获
var result = loadImg(src)
result.then(function() {            // 使用异常捕获,则不需要传失败的回调函数(catch不会捕获reject)
    // throw new Error("Error!")
}).catch(fucntion(ex) {
    // 统一捕获异常
})

Promise串联

var result1 = loadImg("x")
var result2 = loadImg("y")

result1.then(function(img) {        // 执行第一个promise
    console.log("load image x")
    return result2
}).then(function(img) {             // 执行第二个promise
    console.log("load image y")
}).catch(function(ex) {
    // ...
})

Promise all与race

// 接收一个promise对象数组

// 待全部完成后统一执行success
Promise.all([result1, result2]).then(data => {
    console.log(data[0])    // data是数组,包含依次的多个promise返回的内容
    console.log(data[1])
})

// 只要一个完成就执行success
Promise.race([result1, result2]).then(data => {
    console.log(data)       // data为最先执行完成的promise返回的内容
})

async/await

待续