异步
单线程
- 只有一个线程,只能做一件事
- 使用单线程可以避免DOM渲染的冲突
- 浏览器需要渲染DOM
- JS可以修改DOM结构
- JS执行的时候,浏览器的DOM渲染就会暂停
- 两段JS也不能同时执行(都修改DOM就冲突了)
- webworker 支持多线程,但是不能访问DOM
- 解决单线程的方案:使用异步
异步的缺点
- callback 中不能模块化
- 事件执行顺序不能够按照代码书写的方式执行
异步如何执行
- 事件轮询是 JS 实现异步的具体解决方案
- 同步的代码先执行
- 异步函数先放到 异步队列 中
- 待同步函数执行完毕,轮询执行异步队列中的函数
例子:
setTimeout(function() {
console.log('a');
}, 1000);
setTimeout(function() {
console.log('b');
});
console.log('c');
// 最后输出的是 c b a
当页面开始加载,或者说js代码开始执行时。首先执行的是console.log('c');,其次将 console.log(b) 放入到异步队列中,最后过 1000 毫秒之后将 console.log('a') 放入到异步队列中,执行的过程中一直都在轮询去监听执行异步操作。用下面一张图进行解释。

异步队列中有报错,这个不用去管,只是理解这个轮询(event loop)的机制就好。
jQuery 中的 deferred
jQuery 1.5 之后有 deferred 的 API,jQuery 就可以顺利的解决异步 callback 回调地狱的问题了。
- deferred 类似 promise 写法
- 其中包括两类 API
- 第一类:
dtd.resolvedtd.reject - 第二类:
dtd.thendtd.donedetd.fail
- 第一类:
- 使用
$.when()和 return 一个 promise 对象去解决直接调用w.reject()意向不到的错误。通过生成 promise 对象,创建只有被动监听,不能主动修改的环境。
直接上代码:
function waitHandle() {
var dtd = $.Deferred()
var wait = function (dtd) {
var task = function () {
console.log('执行完成');
// 异步成功
dtd.resolve();
// 异步失败
// dtd.reject();
}
setTimeout(task, 1000);
return dtd.promise()
}
return wait(dtd)
}
var w = waitHandle();
// w.reject() // 会直接报错
// 对扩展开放,对修改封闭
$.when(w).then(() => {
console.log('ok 1');
}, () => {
console.log('error 1');
}).then(() => {
console.log('ok 2');
}, () => {
console.log('error 2');
})
Promise
使用图片先后加载的例子解释 promise
function loadImg(src) {
var promise = new Promise((resolve, reject) => {
var img = document.createElement('img')
// throw new Error('test')
img.onload = function() {
resolve(img)
}
img.onerror = function() {
reject('图片不存在')
}
img.src = src
})
return promise
}
var src1 = 'http://images.coohua.com/upload/1bd6b717-8694-45f3-93a2-9766997524fe.jpg'
var result1 = loadImg(src1)
var src2 = 'http://images.coohua.com/upload/05139321-df16-44d4-bd35-55db7d298a421.jpg'
var result2 = loadImg(src2)
result1.then(img => {
console.log('1,' + img.width);
return result2
}).then(img => {
console.log('2.' + img.width);
}).catch(error => {
console.log(error);
})
解决异步的方法
- jQuery Deferred
- promise
- async/await
