题目描述
先看代码............
题中原意为网络请求图片,在请求成功前展示suspense属性的内容。网络请求在js中为异步操作,注释中使用了async函数等待事件循环,但这会使得整个函数返回值也变为promise,如果多几层函数互相调用,就会出现很多的async与await。消除异步传染性要做的,就是要不使用目前js提供的异步解决方案(回调函数,promise,generator,async),仍使得代码逻辑正确。
<body>
<div id="catPic" suspense="<h1>loading...</h1>"></div>
<script>
function getCatPic() {
return window.fetch('https://placekitten.com/1920/1080')
}
// 把
// async function testCom() {
// 改为
function testCom() {
let imgContainer = document.querySelector('#catPic')
imgContainer.innerHTML = imgContainer.getAttribute("suspense")
// 把
// let res = await getCatPic()
// 改为
let res = getCatPic()
res.blob().then(blob => {
let url = URL.createObjectURL(blob)
imgContainer.innerHTML = `<img src="${url}" alt="cat" width="100%">`
})
}
function render(fn) {
// your code ...
}
// 把
// testCom();
// 改为
render(testCom)
</script>
</body>
解决思路
模拟async或generator的执行顺序,在执行到网络请求的时候先暂停,等网络请求回来了再拿回执行权。暂停用抛出错误的方式,但继续执行这里需要取巧,由于网络请求前的代码是渲染loading,所以这里即使执行两次也不会影响正确的逻辑。
那么我们要做的就是第一次执行的时候,到网络请求时抛出错误,网络请求成功后再次执行函数。确定好思路后编码就比较简单了。
编码
<body>
<div id="catPic" suspense="<h1>loading...</h1>"></div>
<script>
function getCatPic() {
return window.fetch('https://placekitten.com/1920/1080')
}
// 把
// async function testCom() {
// 改为
function testCom() {
let imgContainer = document.querySelector('#catPic')
imgContainer.innerHTML = imgContainer.getAttribute("suspense")
// 把
// let res = await getCatPic()
// 改为
let res = getCatPic()
res.blob().then(blob => {
let url = URL.createObjectURL(blob)
imgContainer.innerHTML = `<img src="${url}" alt="cat" width="100%">`
})
}
// testCom();
function render(fn) {
let res = null;
let originFetch = window.fetch
window.fetch = function (...rest) {
if (res) return res;
let p = originFetch.apply(this, rest).then(e => res = e)
throw p
}
try {
fn()
} catch (error) {
error.then(() => {
fn()
window.fetch = originFetch
})
}
}
render(testCom)
</script>
</body>