代码异步和非阻塞 Asynchronous JS | 青训营笔记

79 阅读3分钟

代码异步和非阻塞 Asynchronous JS

const img = document.querySelector('.dog');
// 这一行是异步的,假设图片很大的话在“后台”加载完成再显示会提高用户体验
img.src = 'dog.jpg';
// 只有当图片加载完成才会抛出一个load事件,回调函数被调用,加入一个css效果。
// addEventListener本身不会导致代码异步执行,只是图片在后台异步加载
img.addEventListener('load', function() {
    img.classList.add('fadeIn');
});
p.style.width = '300px';

AJAX: Asynchronous JS And XML(一种过去常用的传输数据的格式), 允许我们用异步的方式去和远程web服务器进行交流。

Promises (ES6)

定义:一个对象,用于存放一个异步操作未来传回的值(container / placeholder)。

用promise的好处:chain promises可以完成一系列的异步操作.

特点:因为跟异步操作有关,所以是时间敏感的,promise的状态会随着时间变化而改变,但一旦变成settled的状态就不可被更改了。一般都只用消费promise对象,例如fetch返回一个promise,但也有时候会需要自己build a new promise。

- consuming promises
  • then() : 只会在promise fulfilled的时候被调用,得到的是resolved value,如果没有resolved value就会() => {...}

response.json() :

  • 所有从fetch函数返回的response对象【所有resolved value】均可调用json方法,这个response已经是一个resolved value。
  • 这个json方法也是异步方法,会返回一个新的promise, 所以可以接着调用then()方法。
const getCountryData = function (country) {
  // Country 1
  fetch(`https://restcountries.com/v3.1/name/${country}`)
    .then(response => {
      return response.json();
    })
    .then(data => {
      renderCountry(data[0]);
      const neighbour = data[0].borders[0];
      if (!neighbour) return;
​
      // Country 2
      return fetch(`https://restcountries.com/v3.1/alpha/${neighbour}`);
      // 不要直接在fetch后面.then()!!!! => 这样又回到了callback hell(在callback中定义callback)
    })
    .then(response => {
      return response.json();
    })
    .then(data => {
      renderCountry(data, 'neighbour');
    }));
};
- 处理Rejected Promises

fetch()唯一reject的情况:用户网络连接断开的情况下发请求。

  • 方法一:then()中传递第二个callback fn。(第一个fn用于处理fuffilled promise, 第二个处理rejected)

    • 比如err => alert(err)
  • 方法二:在链的最末端 .catch(err => alert(err)),可以处理发生在promise链中的任何错误。

finally() 方法有效的原因是then() / catch() 方法都会自动返回一个promise对象。

页面404的话fetch的promise仍会得到fulfilled的状态,所以无法用catch处理。

-Throwing Errors Manually (处理类似404而不是网络断连接的error)
fetch('http://localhost:5500/root').then(response => {
  console.log(response);
    
  // 一些真正想要的错误信息
  // 通过构造函数创建new error, throw会像return一样立马从当前的函数返回
  // promise会立即变成reject状态,这个rejection会沿着promise链向下传播到catch()函数
  if (!response.ok) throw new Error('Country not found');
});
-事件循环/ callback queue / microtasks queue

因为微服务的优先级高于callback fn,所以已经执行的微服务如果源源不断地产生新的微服务的话,就会产生callback queue中任务饥饿的情况。以及如果microtask需要花费较长时间才完成的话,普通callback例如setTimeout注册的回调函数不一定就在指定几秒之后就执行,有延迟。

例子:

console.log('script start');
​
setTimeout(function() {
    console.log('setTimeout');
}, 0);
​
Promise.resolve()
    .then(function() {
        console.log('promise1');
    })
    .then(function() {
        console.log('promise2');
    });
    
console.log('script end');

输出:

script start

script end

promise1

promise2

setTimeout

-自己build Promise
// 给Promise这个构造函数传入的是一个`executor`执行函数
const lotteryPromise = new Promise(function(resolve, reject) {
    // 假设彩票有50%的中奖几率
    if (Math.random() >= 0.5) {
        // 赢了彩票=>一个fulfilled promise,实现了的承诺
        // 调用resolve函数,将promise设置为fulfilled
        // 设置传入的东西为resolved value
        resolve("YOU WIN");
    } else {
        // 会被catch接收
        reject("YOU LOST YOUR MONEY");
    }
})
// 向then方法传入的是resolved value
lotteryPromise.then(res => console.log(res)).catch(err => console.error(err));

zzzz这个人活动快结束了才开始写笔记呜呜呜( ´・・)ノ(._.`)