JS学习-异步JS
异步JS
setTimeout()
我们希望传递给setTimeout()中运行的函数的任何参数,都必须作为列表末尾的附加参数传递给它。
function sayHi(who) {
alert('Hello ' + who + '!');
}
let myGreeting = setTimeout(sayHi, 2000, 'Mr. Universe');
setInterval()
let i = 1;
setInterval(function run() {
console.log(i++);
}, 100);
递归setTimeout()
let i = 1;
setTimeout(function run() {
console.log(i++);
setTimeout(run, 100);
}, 100);
递归setTimeout()和setInterval()有何不同?
- 递归 setTimeout() 保证执行之间的延迟相同,例如在上述情况下为100ms。 代码将运行,然后在它再次运行之前等待100ms,因此无论代码运行多长时间,间隔都是相同的。
- 使用 setInterval() 的示例有些不同。 我们选择的间隔包括执行我们想要运行的代码所花费的时间。假设代码需要40毫秒才能运行 - 然后间隔最终只有60毫秒。
- 当递归使用 setTimeout() 时,每次迭代都可以在运行下一次迭代之前计算不同的延迟。 换句话说,第二个参数的值可以指定在再次运行代码之前等待的不同时间(以毫秒为单位)。
- 当你的代码有可能比你分配的时间间隔更长时间运行时,最好使用递归的setTimeout() ––这将使执行之间的时间间隔保持不变,无论代码执行多长时间,你不会得到错误。
requestAnimationFrame()
setInterval()的现代版本;在浏览器下一次重新绘制显示之前执行指定的代码块,从而允许动画在适当的帧率下运行,而不管它在什么环境中运行。
由于大多数屏幕的刷新率为60Hz,因此在使用web浏览器时,可以达到的最快帧速率是每秒60帧(FPS)。然而,更多的帧意味着更多的处理,这通常会导致卡顿和跳跃-也称为丢帧或跳帧。
如果您有一个刷新率为60Hz的显示器,并且希望达到60fps,则大约有16.7毫秒(1000/60)来执行动画代码来渲染每个帧。
//在函数的末尾,以 requestAnimationFrame() 传递的函数作为参数进行调用,这指示浏览器在下一次显示重新绘制时再次调用该函数。
(function draw() {
// Drawing code goes here
requestAnimationFrame(draw);
})();
//setInterval()
setInterval(function draw(){},17)
传递给 requestAnimationFrame() 函数的实际回调也可以被赋予一个参数(一个时间戳值),表示自 requestAnimationFrame() 开始运行以来的时间。
let startTime = null;
(function draw(timestamp) {
if(!startTime) {
startTime = timestamp
}
currentTime = timestamp - startTime;
// Do something based on current time
requestAnimationFrame(draw);
})()
//撤销requestAnimationFrame()
cancelAnimationFrame(rAF);
异步处理
-
创建promise时,它既不是成功也不是失败状态。这个状态叫作pending(待定)。
-
当promise返回时,称为 resolved(已解决).
- 一个成功resolved的promise称为fullfilled(实现)。它返回一个值,可以通过将.then()块链接到promise链的末尾来访问该值。.then()块中的执行程序函数将包含promise的返回值。
- 一个不成功resolved的promise被称为rejected(拒绝)了。它返回一个原因(reason),一条错误消息,说明为什么拒绝promise。可以通过将.catch()块链接到promise链的末尾来访问此原因。
promise与事件监听器类似,但有一些差异:
* 一个promise只能成功或失败一次。它不能成功或失败两次,并且一旦操作完成,它就无法从成功切换到失败,反之亦然。
* 如果promise成功或失败并且你稍后添加成功/失败回调,则将调用正确的回调,即使事件发生在较早的时间。
chooseToppings()
.then(toppings => placeOrder(toppings))
.then(order => collectOrder(order))
.then(pizza => eatPizza(pizza))
.catch(failureCallback);
//等同于
chooseToppings()
.then(placeOrder)
.then(collectOrder)
.then(eatPizza)
.catch(failureCallback);
注意:在真实的应用程序中,你的.catch()块可以重试获取图像,或显示默认图像,或提示用户提供不同的图像URL等等。
//fetch(imgUrl)然后赋给img再展示到页面
fetch('coffee.jpg').then(response => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
} else {
return response.blob();
}
}).then(myBlob => {
let objectURL = URL.createObjectURL(myBlob);
let image = document.createElement('img');
image.src = objectURL;
document.body.appendChild(image);
}).catch(e => {
console.log('There has been a problem with your fetch operation: ' + e.message);
});
响应多个异步任务
Promise.all()静态方法,将一个promises数组作为输入参数,并返回一个新的Promise对象,只有当数组中的所有promise都满足时才会满足。
Promise.all([a, b, c]).then(values => {...});
// 获取信息以在内容上动态填充页面上的UI功能。
// 在许多情况下,接收所有数据然后才显示完整内容,而不是显示部分信息。
异步操作结束处理
在promise完成后,你可能希望运行最后一段代码,无论它是否已实现(fullfilled)或被拒绝(rejected)。
myPromise.then(response => {
doSomething(response);
runFinalCode();
}).catch(e => {
returnError(e);
runFinalCode();
})
//等同于
myPromise.then(response => {
doSomething(response);
}).catch(e => {
returnError(e);
}).finally(() => {
runFinalCode();
});