异步编程 -- 使用Promise、Generator、async/await 规避回调地狱

关于回调地狱

在异步编程中,许多操作都会放在回调函数(callback)中,每增加一个异步请求,就会多添加一层回调函数的嵌套,多个异步操作就形成了强耦合,只要有一个操作需要修改,它的上层回调函数和下层回调函数,可能都要跟着修改,过多的回调也就会导致陷入“回调地狱”。


规避回调地狱的方法:

promise对象

它不是新的语法功能,而是一种新的写法,允许将回调函数的嵌套,改成链式调用。

  • Promise对象是一个构造函数,接受一个带了resolvereject参数的函数;

在状态由pending变为fulfilled时,从resolve中将value传出;

在状态由pending变为rejected时,将error抛出

const promise = new Promise(function(resolve, reject) {
  // ... some code
  if (/* 异步操作成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});
  • Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数。
promise.then(function(value) {
  // success
}, function(error) {
  // failure
});
  • Promise 提供then方法加载回调函数,catch方法捕捉执行过程中抛出的错误。

或者这样捕获error:

getJSON('/posts.json').then(function(posts) {
  // ...
}).catch(function(error) {
  // 处理 getJSON 和 前一个回调函数运行时发生的错误
  console.log('发生错误!', error);
});
  • finally方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。
promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});

Promise.all | Promise.race方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。

Generator 函数

特征:1.function关键字与函数名之间有一个星号;2.函数体内部使用yield表达式,定义不同的内部状态

function* helloWorldGenerator() {
  yield 'hello';
  yield 'world';
  return 'ending';
}

var hw = helloWorldGenerator();

调用遍历器对象的next方法,使得指针移向下一个状态。

hw.next()
// { value: 'hello', done: false }

hw.next()
// { value: 'world', done: false }

hw.next()
// { value: 'ending', done: true }

hw.next()
// { value: undefined, done: true }

for...of循环可以自动遍历 Generator 函数时生成的Iterator对象,且此时不再需要调用next方法。

function* foo() {
  yield 1;
  yield 2;
  yield 3;
  yield 4;
  yield 5;
  return 6;
}

for (let v of foo()) {
  console.log(v);
}
Thunk 函数
  • Thunk 函数是自动执行 Generator 函数的一种方法。

在 JavaScript 语言中,Thunk 函数替换的不是表达式,而是多参数函数,将其替换成一个只接受回调函数作为参数的单参数函数。

// 正常版本的readFile(多参数版本)
fs.readFile(fileName, callback);

// Thunk版本的readFile(单参数版本)
var Thunk = function (fileName) {
  return function (callback) {
    return fs.readFile(fileName, callback);
  };
};
var readFileThunk = Thunk(fileName);
readFileThunk(callback);
  • Thunk函数实现上是针对多参数的currying(柯里化),来实现对函数的惰性求值。

  • 任何函数,只要参数有回调函数,就能写成Thunk函数的形式。

var readFileThunk = fs.readFile.bind(null, './oranges.txt', 'utf8');
readFileThunk(someCallback);
async/await

async 函数其实就是 Generator 函数的语法糖

  • await后一般是一个Promise对象。

  • async函数返回一个 Promise对象时,就可以使用then方法添加回调函数。

  • 当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。

const asyncReadFile = async function () {
  const f1 = await readFile('/etc/fstab');
  const f2 = await readFile('/etc/shells');
  console.log(f1.toString());
  console.log(f2.toString());
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值