JS 处理异步的几种方法

2019-11-22  本文已影响0人  正义国王

1. 异步JavaScript

在 JS 中,经常要处理一些异步回调,比如从网络获取文件,访问数据库,从网络摄像头获得视频流;

例如下面的代码,因为从服务器上获取一个图像需要时间,下面的代码可能不能正常工作;

var response = fetch('myImage.png');
var blob = response.blob();
// display your image blob in the UI somehow

那么如何解决这类问题呢?方法有很多:可分为异步callbacks(回调函数)和 其他方法(promise、async\await、generator)。下面一一介绍

2. 异步callbacks

以使用 XMLHttpRequest API 为例:

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);

这里我们在loadAsset函数中发出网络请求,但注意我们向loadAsset函数中传入了一个 回调函数displayImage); 当浏览器收到服务器返回来的数据时,会触发onload事件,并把响应作为参数传递给回调函数去处理。

这样,我们就解决了之前的问题:还未收到响应数据就执行处理函数。

3. Promise

Promise 是专门为处理异步逻辑而设计的,它让异步回调过程更加清晰。让我们看看上面的代码使用Promise改写是怎样的:

function loadAsset(url, type) {
  return new Promise((resolve, reject) => {
    let xhr = new XMLHttpRequest();
    xhr.open("GET", url);
    xhr.responseType = type;

    xhr.onload = function() {
      resolve(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").then(data => {
  displayImage(data);
});

比较后我们会发现,这里不再需要给 loadAsset传入回调函数,Promise帮我们处理了这个逻辑,在收到响应后,由于我们使用了resolve返回响应数据,我们直接在then方法中就能拿到我们要的数据了!

虽然代码看起来多了一点,但是逻辑看起来却更清楚了,特别是遇到 回调函数嵌套 的问题。这就是使用Promise的好处。

4. 生成器(Generator)

让我们看一下 Generator 的示例:

function* say(){
    yield "开始";
    yield "执行中";
    yield "结束";
}
let it = say(); // 调用say方法,得到一个迭代器
console.log(it.next()); // { value: '开始', done: false }
console.log(it.next()); // { value: '执行中', done: false }
console.log(it.next()); // { value: '结束', done: false }
console.log(it.next()); // { value: undefined, done: true }

生成器函数定义时在function关键字后面多加一个*号。它和普通函数不同,普通函数一次执行完所有代码,但它可以通过yield关键字将函数的执行挂起,再外部在通过调用next方法,让函数继续执行,直到遇到下一个yield,或函数执行完毕。

这样,异步操作也可以变得和同步操作一样。

5. async/await

async/await 是常用的处理异步逻辑的方法,它其实就是生成器的语法糖。

async function getData(){
  var response = await fetch('myImage.png');
  var blob = response.blob();
}

在异步处理前加 await ,这样函数将等待异步流程结束后才执行之后的代码。

上一篇下一篇

猜你喜欢

热点阅读