一) Callbacks
异步callbacks其实就是函数,只不过是作为参数传递给那些在后台执行的其他函数. 当那些后台运行的代码结束,就调用callbacks函数,通知你工作已经完成,或者其他有趣的事情发生了。使用callbacks有一点老套,在一些老派但经常使用的API里面,你会经常看到这种风格。
- 举个例子,异步callback 就是
addEventListener()
方法中的第二个参数。第一个参数是侦听的事件类型,第二个是事件发生时调用的回调函数。
button.addEventListener('click',() => {
alert("You clicked me!")
let newElem = document.createElement('p')
newElem.textContent = 'This is a new-element.'
document.body.appendChild(newElem)
})
-
当我们把回调函数作为一个参数传递给另一个函数时,仅仅是把回调函数作为参数传递过去,回调函数并没有立刻执行,回调函数会在包含它的函数的某个地方异步执行,包含函数负责在合适的时候执行回调函数。
-
你可以自己写一个简易的,包含回调函数的函数。来看另外一个例子,XMLHttpRequest
function loadAsset(url,type,callback) {
let xhr = new XMLHttpRequest()
xhr.open("GET",url)
xhr.responseType = type
xhr.onload = function() {
callback(xhr.response)
}
xhr.send()
}
function displayImage(blob) {
let objectURL = URL.createObjectURL(blob)
let image = document.createElement("img")
image.src = objectURL
document.body.appendChild(image)
}
loadAsset("coffee.jpg","blob",displayImage)
-
创建
displayImage()
函数,简单的把blob传递给它,生成objectURL,然后再生成一个image元素,把objectURL作为image的源地址,最后显示这张图片。 接着,我们创建loadAsset()
函数,把url,type,以及callback都作为参数。函数用XMLHttpRequest
获取给定url资源,在获得资源响应后再把响应作为参数传递给回调函数去处理。 -
不是所有的回调函数都是异步的。比如
Array.prototype.forEach()
,forEach需要的参数是一个回调函数,回调函数本身带有两个参数,数组元素和索引值。它无需等待任何事情,立即运行。
const gods = ['Apollo','Artemis','Ares','Zeus']
gods.forEach(function (eachName,index){
console.log(index + "." + eachName)
})
二) Promises
Promises 是新派的异步代码,现代的
web APIs
经常用到。
-
fetch()
就是一个很好的例子。fetch只需要一个参数,资源的网络url,然后返回一个promise
,promise表示异步操作完成或失败的对象。可以说,它代表了一种中间状态。 本质上,这是浏览器说“我保证尽快给您答复”的一种方式,因此得名 Promise
fetch('products.json').then(function(response) {
return response.json();
}).then(function(json) {
products = json;
initialize();
}).catch(function(err) {
console.log('Fetch problem: ' + err.message);
});
- 像promise这样的异步操作被放入事件队列中,事件队列在主线程完成处理后运行,这样它们就不会阻止后续JavaScript代码的运行。排队操作将尽快完成,然后将结果返回到JavaScript环境。
三) Promises 与 Callbacks 比较
promises与旧式callbacks有一些相似之处。它们本质上其实就是返回一个
object
对象,您可以将回调函数附加到该对象上,而不必将回调作为参数传递给另一个函数。
Promise是专门为异步操作而设计的,与Callbacks相比,具有如下优点:
- 您可以使用多个
then()
操作,将多个异步操作链接在一起,并将其中一个操作的结果作为输入传递给下一个操作。这种链接方式对回调来说要难得多,会使回调以混乱的末日金字塔
告终。 (也称为回调地狱)。 - Promise总是严格按照它们放置在事件队列中的顺序调用。
- 错误处理要好得多,所有的错误都由块末尾的一个
.catch()
块来处理,而不是在金字塔
的每一层单独处理。
网友评论