实现方式

回调函数

回调函数将一个函数以参数的形似传递到另一个函数, 控制其执行的时机, 以达到异步的效果

在Node.js读写文件的时候经常用到:

const fs = require('fs');
fs.readFile('config.json', (err, data) => {
  if (err) {
    console.error(err);
  } else {
    console.log(data);
  }
});

又比如,jquery的ajax就是一个典型的异步回调方法:

$.ajax({
  type: 'POST',
  url: './index.php',
  contentType: 'application/x-www-form-urlencoded',
  data: {
    name: 'quanzaiyu',
    password: 123
  },
  success: function (data) {},
  error: function (err) {},
  complete: function (data) {}
});

但是如果在请求的时候, 一个接口依赖于另一个接口的返回值, 将会类似于如下嵌套:

$.get('url', function(){
    $.get('url1', function(){
        $.get('url2', function(){
        }, 'json');
    }, 'json');
}, 'json');

“回调函数,内嵌回调函数” 可以无穷尽的内嵌,结果就是各个部分之间高度耦合,流程混在一起,每个任务只能指定一个回调函数。最终造成的结果就会嵌入回调地狱,很可能就像这样了——结尾是无止境的, 也可能造成不可预估的结果

图片来源于: https://tutorialzine.com/media/2017/07/callback-hell.jpg

Promise

所谓 Promise, 就是一个对象,用来传递异步操作的消息。它代表了某个未来才会知道结果的事件 (通常是一个异步操作),并且这个事件提供统一的 API,可供进一步处理。

Promise要解决的就是回调函数回调地狱的问题, 通过更直观的方式避免错误的产生

Promise 对象有以下两个特点:

  • (1)对象的状态不受外界影响。Promise 对象代表一个异步操作,有三种状态:Pending(进行中)、Resolved(已完成,又称 Fulfilled)和 Rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是 Promise 这个名字的由来,它的英语意思就是「承诺」,表示其他手段无法改变。
  • (2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise 对象的状态改变,只有两种可能:从 Pending 变为 Resolved 和从 Pending 变为 Rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果。就算改变已经发生了,你再对 Promise 对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。

一个简单的Promise使用方式:

fun().then(res => {}).catch(e => {})

从回调函数向Promise转换

一个普通的回调函数可以封装成Promise, 比如:

function promiseAjax(url, data) {
  return new Promise((resolve, reject) => {
    $.ajax({
      type: 'POST',
      url,
      data,
      success: function (res) {
        resolve(res)
      },
      error: function (e) {
        reject(e)
      }
    });
  })
}
promiseAjax('http://test.com').then(res => {}).catch (e => {})

还是拿Node.js读写文件举个例:

const fs = require('fs');
const readFile = file => new Promise((resolve, reject) => {
  fs.readFile(file, (err, data) => {
    if (err) {
      reject(err);
    } else {
      resolve(data);
    }
  });
});
readFile('config.json').then(data => {
  console.log(data);
}).catch(err => {
  console.error(err);
});

生成器与迭代器

先理解两个概念:生成器是一个返回迭代器的函数;那么迭代器就是生成器执行后返回的结果(对象)。所以,生成器是函数,迭代器是对象(很容易弄混的两个概念)。

首先,生成器是一个函数,这是一个特殊的函数,函数定义如下:

// 这就是一个生成器(函数)
function *createIterator() {
    const a = yield 1;
    const b = yield a + 2;
    yield b + 3;
}
// 这就是一个迭代器(对象)
const iterator = createIterator();
// 注释部分是next方法执行的返回值
iterator.next();    // {value: 1, done: false}      执行完这句并没有给a赋值
iterator.next();    // {value: 3, done: false}      执行这句的时候才会给a赋值1
iterator.next(5);   // {value: 8, done: false}      执行这句的时候才会给b赋值5
iterator.next();    // {value: undefined, done: true}

async..await

Async/Await是一个很久就令人期待的 JavaScript 功能,它让使用异步函数更加愉快和容易理解。它是基于 Promise 的并且和现存的所有基于 Promise 的 API 相兼容。 Async/Await 版本的代码更短并且可读性更强, 使得异步方法形同同步方法一样地使用,作为Promise的语法糖非常甜!

从Promise转换为async..await

只要返回的是一个 Promise 对象, 都可以使用async...await的调用方式, 比如刚才的 promiseAjax 方法:

async function testAjax () {
  try {
    let res = await promiseAjax()
    console.log(res)
  } catch (e) {
    console.log(e)
  }
}

看上去是同步的代码,实际执行是异步的

注意, 在使用时需要进行 try..catch, 以免产生错误

MIT Licensed | Copyright © 2018-present 滇ICP备16006294号

Design by Quanzaiyu | Power by VuePress