14.回调地狱与 Promise

2019-04-16  本文已影响0人  璎珞纨澜

回调地狱

为了保证异步代码的执行顺序,将异步代码嵌套到回调函数中,当异步的方法多了,就会产生回调地狱(callback hell),这样的代码丑陋且难以维护。


回调地狱

读取三个文件 - 无法保证顺序的代码:

var fs = require('fs')

fs.readFile('./data/a.txt', 'utf8', function (err, data) {
  if (err) {
    throw err
  }
  console.log(data)
})

fs.readFile('./data/b.txt', 'utf8', function (err, data) {
  if (err) {
    throw err
  }
  console.log(data)
})

fs.readFile('./data/c.txt', 'utf8', function (err, data) {
  if (err) {
    throw err
  }
  console.log(data)
})

读取三个文件 - 通过回调嵌套的方式来保证执行顺序:

var fs = require('fs')

fs.readFile('./data/a.txt', 'utf8', function (err, data) {
  if (err) {
    throw err
  }
  console.log(data)
  fs.readFile('./data/b.txt', 'utf8', function (err, data) {
    if (err) {
      throw err
    }
    console.log(data)
    fs.readFile('./data/c.txt', 'utf8', function (err, data) {
      if (err) {
        throw err
      }
      console.log(data)
    })
  })
})

ES6 Promise

参考文档:http://es6.ruanyifeng.com/#docs/promise

为了解决以上编码方式带来的问题(回调地狱嵌套),所以在 EcmaScript 6 中新增了一个 API:Promise

基本用法:

var fs = require ('fs')

// 创建 Promise 容器
var promise = new Promise(function (resolve, reject) { // 这里的 function 是异步任务
  if (err) {
    reject(err) // 任务失败,把容器的 Pending 状态变为 Rejected
  } else {
    resolve(data) // 任务成功,把容器的 Pending 状态变为 Resolved
  }
})

promise
  .then(function (data) { 
    console.log(data) // 第一个参数: function 就是容器中的 resolve 函数
  }, function (err) {
    console.log('读取文件失败了',err) // 第二个参数: function 就是容器中的 reject 函数
  })

读取三个文件 - 使用 Promise 的方式来保证执行顺序:

var fs = require('fs')

var p1 = new Promise(function (resolve, reject) {
  fs.readFile('./data/a.txt', 'utf8', function (err, data) {
    if (err) {
      reject(err)
    } else {
      resolve(data)
    }
  })
})

var p2 = new Promise(function (resolve, reject) {
  fs.readFile('./data/b.txt', 'utf8', function (err, data) {
    if (err) {
      reject(err)
    } else {
      resolve(data)
    }
  })
})

var p3 = new Promise(function (resolve, reject) {
  fs.readFile('./data/c.txt', 'utf8', function (err, data) {
    if (err) {
      reject(err)
    } else {
      resolve(data)
    }
  })
})

p1
  .then(function (data) {
    console.log(data)
    return p2
  }, function (err) {
    console.log('读取a文件失败了', err)
  })
  .then(function (data) {
    console.log(data)
    return p3
  }, function (err) {
    console.log('读取b文件失败了', err)
  })
  .then(function (data) {
    console.log(data)
    console.log('end')
  }, function (err) {
    console.log('读取c文件失败了', err)
  })

解读:

封装 Promise API

上面的代码示例解决了嵌套代码不美观的问题,但是没有解决代码重复冗余的问题,因此我们这里把 Promise 封装成可以重复调用的 API

var fs = require('fs')

function pReadFile(filePath) {
  return new Promise(function(resolve, reject) {
    fs.readFile(filePath, 'utf8', function (err, data) {
      if (err) {
        reject(err)
      } else {
        resolve(data)
      }
    })
  })
}

pReadFile('./data/a.txt')
  .then(function (data) {
    console.log(data)
    return pReadFile('./data/b.txt')
  }, function (err) {
    console.log('读取a文件失败了', err)
  })
  .then(function (data) {
    console.log(data)
    return pReadFile('./data/c.txt')
  }, function (err) {
    console.log('读取b文件失败了', err)
  })
  .then(function (data) {
    console.log(data)
  }, function (err) {
    console.log('读取c文件失败了', err)
  })

上一篇 下一篇

猜你喜欢

热点阅读