JavaScript 异步
程序员文章站
2024-01-28 09:35:52
...
JS是单线程执行,避免DOM渲染冲突:
- 浏览器需要渲染DOM;
- JS可以修改DOM,修改时浏览器会暂停渲染;
- 两段JS同时执行会发生冲突;
- webworker支持多线程,但不能访问DOM。
同步:代码顺序执行,中间可能会阻塞
console.log(100)
alert(200) // 同步执行,点确认前会阻塞
console.log(300)
异步:不考虑执行结果(或通过回调获取执行结果),调用立即返回;
使用异步的场景:在可能发生等待、且等待过程中不能阻塞(像alert一样):
-
setTimeout
,setInterval
; - ajax请求,动态
<img>
加载; - 事件绑定。
通过异步解决执行效率低仍存在问题:
- 可读性差(不是按顺序执行);
- 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(事件轮询):
- 顺序执行所有同步函数;
- 需要等待的异步函数(延时、AJAX)会在等待完成后再暂存在异步队列(单线程);
- 轮询异步队列,依次取出函数执行。
$.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.resolve
,dtd.reject
-
dtd.then
,dtd.done
,dtd.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
待续
上一篇: vue拖拽排序插件vuedraggable使用方法详解
下一篇: AsyncTask异步执行