都2020年了,你还没有搞懂异步、回调、promise么?(二)

211 阅读4分钟

Promise

  • 回调地狱

说白了就是异步里面套了一个异步 ,异步依赖于上一个异步的结果 就得嵌套进去

const fs = require("fs");
fs.readFile('./data/a.txt', function (err, data) {//字符串二进制转中文可以在这的第二个参数设置为'utf8'
    if (err) {
        // return console('读取失败')
        //抛出异常 
        // todo 1.阻止程序的执行
        // todo 2.把错误消息打印到控制台
        throw err
    }
    console.log('xxx', data.toString())
})
fs.readFile('./data/b.txt', function (err, data) {//字符串二进制转中文可以在这的第二个参数设置为'utf8'
    if (err) {
        throw err
    }
    console.log('xxx', data.toString())
})
fs.readFile('./data/c.txt', function (err, data) {//字符串二进制转中文可以在这的第二个参数设置为'utf8'
    if (err) {
        throw err
    }
    console.log('xxx', data.toString())
})
// 输出顺序取决于文件的大小 其实也不一定 底层是一个多线程的东西  不一定谁先谁后  无法保证顺序
  • 通过回调嵌套的方式来保证顺序
const fs = require("fs");
fs.readFile('./data/a.txt', function (err, data) {//字符串二进制转中文可以在这的第二个参数设置为'utf8'
    if (err) {
        // return console('读取失败')
        //抛出异常 
        // todo 1.阻止程序的执行
        // todo 2.把错误消息打印到控制台
        throw err
    }
    console.log('xxx', data.toString())
    fs.readFile('./data/b.txt', function (err, data) {//字符串二进制转中文可以在这的第二个参数设置为'utf8'
    if (err) {
        // return console('读取失败')
        //抛出异常 
        // todo 1.阻止程序的执行
        // todo 2.把错误消息打印到控制台
        throw err
    }
    console.log('xxx', data.toString())
    fs.readFile('./data/c.txt', function (err, data) {//字符串二进制转中文可以在这的第二个参数设置为'utf8'
    if (err) {
        // return console('读取失败')
        //抛出异常 
        // todo 1.阻止程序的执行
        // todo 2.把错误消息打印到控制台
        throw err
    }
    console.log('xxx', data.toString())
})
})
})
//b必须放在a的回调函数中
  • 为了解决以上编码方式带来的问题(回调地狱嵌套)、在es6中新增了一个API:Promise
  • 刚开始的时候就是pending正在执行状态 状态只能变成其中一种
  • 在es6中新增了一个API、promise是一个构造函数
// todo 在es6中新增了一个API、promise是一个构造函数
const fs = require('fs')
// 1.创建Promise容器 给别人一个承诺
console.log(1)
// promise一旦创建,就会立即执行里面(function中)的代码  承诺本身不是异步的 承诺里面的函数(任务)是异步的
var p1 = new Promise(function(resolve,reject){//形参
  //p1 是一个实例   new promise得到的
  console.log(2)
 fs.readFile('./data/a.txt','utf8',(err,data)=>{//promise是一个容器 但是往往里面封装了一个异步任务
     if(err){
        //  失败了  承诺容器中的任务失败了
        // console.log(err)
        reject(err)//把容器的pending状态改为reject  要告诉别人  不要自己抛出了
     }else{
       //  成功了  承诺容器中的任务成功了
       console.log(3)
        // 也就是说这里调用的resolve方法实际上就是then方法中传递的那个function
       resolve(data)//把容器的pending状态改为resolved  回调函数   在这里调用
     }
 })
})

console.log(4)
// p1就是承诺
// 当p1 成功了,然后做指定的操作
// then 当中接受的function  就是容器中的resolve函数
p1.then(function(data){
    console.log(data)//定义  这个data 就是resolve中的data
},function(err){
  console.log('输出文件失败',err)//reject方法
})
  • 建立3个promise实例
p1,p2,p3
p1.then(function(data){
    console.log(data)
    // 当p1读取成功的时候,当前函数的return 的结果就可以在后面的then中 function接受到
    // 当你return 123 后面就接受到 123  没有return 就会返回undefined
    //当return 一个promise对象的时候,后面的then中方法的第一个参数会作为p2 的resolve
    return p2
},function(err){
  console.log('输出文件失败',err)//reject方法
}).then(function(data){//p2 的resolve
  console.log(data)
  return p3
}).then((data)=>{//p3的resolve
  console.log(data)
})//链式调用
  • 封装promise版本的readfile
// todo 在es6中新增了一个API、promise是一个构造函数
const fs = require('fs')

function pReadFile(filePath){
    return new Promise(function(resolve,reject){//形参
        // console.log(2)
     fs.readFile(filePath,'utf8',(err,data)=>{
         if(err){
            //  失败了  承诺容器中的任务失败了
            // console.log(err)
            reject(err)//把容器的pending状态改为reject
         }else{
           //  成功了  承诺容器中的任务成功了
          //  console.log(3)
          // 也就是说这里调用的resolve方法实际上就是then方法中传递的那个function
           resolve(data)//把容器的pending状态改为resolved
         }
     })
    })
}
pReadFile('./data/a.txt')
 .then(function(data){//promise对象才可以then
     console.log(data)
     return pReadFile('./data/b.txt')//这个方法一调用就会return 一个promise对象
 })
 .then(function(data){
    console.log(data)
    return pReadFile('./data/c.txt')
})
.then(function(data){
    console.log(data)
})

参考文章: 从异步概念到callback回调函数到promise

es6promise