promise学习,多看几次。含node,ES6知识

一、引出promise解决回调地狱

需求:你要封装一个方法,我给你一个要读取文件的路径,你这个方法能帮我读取文件,并把内容返回给我

目录图片
5bde238b30aead333d0ea13b542bbf82.png
三个txt里面的内容分别是111,222,333

1、模块调用声明:

Node-核心模块(fs、path)

const fs = require('fs')//fs为文件模块
const path = require('path')//path为系统路径模块

2、使用readFile方法,进行文件数据的读取。

fs.readFile(filename, [options], callback)

filename为文件路径及名称,

[options]为具体选项配置,包括数据的编码方式,

callback为回调函数,进行相应的错误处理及提示。

①普通读取文件的方式
//__dirname :表示当前执行js文件的所属目录的绝对路径 ,通过拼接可以获得要操作文件的绝对路径。
 fs.readFile(path.join(__dirname, './files/1.txt'), 
 utf-8',
 (err, dataStr) => {
  if (err) throw err
  console.log(dataStr)
}) 

终端命令输:node 首个文件名字-再按Tab键能自动补全

②使用回调得到方法内部的返回值
function getFileByPath(fpath){
  fs.readFile(fpath,'utf-8',(err,dataStr) => {
    if(err) throw err
    console.log(dataStr) //=>undefined
  })
}
 var result = getFileByPath(path.join(__dirname, './files/1.txt'))
console.log(result)  //=>111

5d69b6ca4b5cc21d9f6b9d6b09d1997d.png

主程序跑到19行,发现没有return,一个方法没有return会返回undefined。拿不到方法内部异步函数的返回值。

function getFileByPath(fpath,callback){
  fs.readFile(fpath,'utf-8',(err,dataStr) => {
    if(err) throw err
    callback(dataStr)
  })
}
getFileByPath(path.join(__dirname,'./files/1.txt'),(dataStr)=>{
  console.log(dataStr+'---') //----> 111---
})

但是以上方法并不是很好,如果路径错误就会终止,无论结果如何都要告诉用户。


我们可以规定一下, callback 中,有两个参数,第一个参数,是 失败的结果;第二个参数是成功的结果;
同时,我们规定了: 如果成功后,返回的结果,应该位于 callback 参数的第二个位置,此时, 第一个位置 由于没有出错,所以,放一个 null;  如果失败了,则 第一个位置放 Error对象,第二个位置防止一个 undefined

function getFileByPath(fpath,callback){
  fs.readFile(fpath,'utf-8',(err,dataStr) => {
    //如果报错,进入if分支后,if后面的代码就没有必要执行了
    if(err) return callback(err)//先调用这个函数,函数执行完立结束
    callback(null,dataStr)
  })
}
getFileByPath(path.join(__dirname,'./files/1.txt'),(err,dataStr)=>{
  if(err) return console.log(err.message)
  console.log(dataStr)
})

2056d67c15b5376c4900e4f0e3894b3f.png

③封装读取文件方法提高版

把刚才的回调分成两个

function getFileByPath(fpath,succcCb,errCb){
  fs.readFile(fpath,'utf-8',(err,dataStr) => {
    //如果报错,进入if分支后,if后面的代码就没有必要执行了
    if(err) return errCb(err)//先调用这个函数,函数执行完立结束
    succcCb(dataStr)
  })
}
getFileByPath(path.join(__dirname,'./files/1eee.txt'),function(data){
  console.log(data+'成功!');
},function(err){
  console.log('使用回调函数处理失败的结果:'+err.message);
})

fe57cb43bff66478227dd4991cfa878e.png

需求: 先读取文件1,再读取文件2,最后再读取文件3

// 回调地狱
// 使用 ES6 中的 Promise,来解决 回调地狱的问题;
// 问: Promise 的本质是要干什么的:就是单纯的为了解决回调地狱问题;并不能帮我们减少代码量;
getFileByPath(path.join(__dirname, './files/1.txt'), function (data) {
  console.log(data)
  getFileByPath(path.join(__dirname, './files/2.txt'), function (data) {
    console.log(data)
    getFileByPath(path.join(__dirname, './files/3.txt'), function (data) {
      console.log(data)
    })
  })
})

回调地狱如图所示:
d728c1a8ebc5390980f5b88b8b103cc6.png

3、可以使用writeFile方法,将数据写入文件到某个文件夹下。

fs.writeFile(filename, data, [options], callback)

filename为具体的文件保存路径地址,

data为具体要写入文件的数据对象,

[options]为具体的保存文件配置,编码格式等,

callback为具体的回调函数,进行相应的错误捕捉及提示。

二、promise基本概念

在JavaScript的世界中,所有代码都是单线程执行的。由于这个“缺陷”,导致JavaScript的所有网络操作,浏览器事件,都必须是异步执行。异步执行可以用回调函数实现

console窗口输入console.dir(promise)
43b7ef1bdd32f18a21575156e3736c17.png

  1. Promise 是一个 构造函数,既然是构造函数, 那么,我们就可以  new Promise() 得到一个 Promise 的实例;

  2. 在 Promise 上,有两个函数,分别叫做 resolve(成功之后的回调函数) 和 reject(失败之后的回调函数)

  3. 在 Promise 构造函数的 Prototype 属性上,有一个 .then() 方法,也就说,只要是 Promise 构造函数创建的实例,都可以访问到 .then() 方法

  4. Promise 表示一个 异步操作;每当我们 new 一个 Promise 的实例,这个实例,就表示一个具体的异步操作;

  5. 既然 Promise 创建的实例,是一个异步操作,那么,这个 异步操作的结果,只能有两种状态:

    5.1 状态1: 异步执行成功了,需要在内部调用 成功的回调函数 resolve 把结果返回给调用者;
    5.2 状态2: 异步执行失败了,需要在内部调用 失败的回调函数 reject 把结果返回给调用者;
    5.3 由于 Promise 的实例,是一个异步操作,所以,内部拿到 操作的结果后,无法使用 return 把操作的结果返回给调用者; 这时候,只能使用回调函数的形式,来把 成功 或 失败的结果,返回给调用者;

  6. 我们可以在 new 出来的 Promise 实例上,调用 .then() 方法,【预先】 为 这个 Promise 异步操作,指定 成功(resolve) 和 失败(reject) 回调函数;
    var promise = new Promise()
     注意:这里 new 出来的 promise, 只是代表 【形式上】的一个异步操作;
    什么是形式上的异步操作:就是说,我们只知道它是一个异步操作,但是做什么具体的异步事情,目前还不清楚。
    下面是一个具体的异步操作,其中,使用 function 指定一个具体的异步操作

var promise = new Promise(function(){
    //这个 function 内部写的就是具体的异步操作!!!
})

new 的时候,除了能够得到 一个 promise 实例之外,还会立即调用 我们为 Promise 构造函数传递的那个 function,执行这个 function 中的 异步操作代码;

const fs = require('fs')
var promise = new Promise(function(){
    fs.readFile('./files/2.txt','utf-8',(err,dataStr) => {
        if(err) throw err
        console.log(dataStr)
    });
})

可以创建一个函数,函数没有被调用,promise不会执行

const fs = require('fs')
  function getFileByPath (fpath){//没有被调用,promise不会执行
    var promise =new Promise(function(resolve, reject) {
      fs.readFile(fpath,'utf-8',(err,dataStr) => {
        if(err) throw err
        console.log(dataStr)
      })
    })
  }
  getFileByPath('./files/2.txt')

但是以上的代码并没有给用户返回值,失败直接throw,成功直接输出了。直接return也不行,因为是异步操作。然而我们想要的是: 给路径,返回读取到的内容
函数内部的变量没有return出去,外部是访问不到的

68e7bd726cbd0f1caf41c9149681b144.png

function getFileByPath(fpath) {
  return new Promise(function (resolve, reject) {//resolve, reject是形参
    fs.readFile(fpath, 'utf-8', (err, dataStr) => {
      if (err) return reject(err)
      resolve(dataStr)
    })
  })
}
getFileByPath('./files/2.txt')
  .then(function (data) {
    console.log(data + '-------')
  }, function (err) {
    console.log(err.message)
  }) 

三、使用promise解决回调地狱

要求:先读取文件1,在读取2,最后读取3 注意: 通过 .then 指定 回调函数的时候,成功的 回调函数,必须传,但是,失败的回调,可以省略不传
①标准使用方法:通过3个.then的串联解决了回调地狱,在上一个 .then 中,返回一个新的 promise 实例,可以继续用下一个 .then 来处理

 1 const fs = require('fs')
 2 function getFileByPath(fpath){
 3   return new Promise(function (resolve,reject){
 4     fs.readFile(fpath,'utf-8',(err,dataStr)=>{
 5       if(err) return reject(err)
 6       resolve(dataStr)
 7     })
 8   })
 9 }
10 getFileByPath('./files/1.txt')
11 .then(function(data){
12   console.log(data)
13   //读取文件2
14   return getFileByPath('./files/2.txt')
15 })
16 .then(function(data){
17   console.log(data)
18   return getFileByPath('./files/3.txt')
19 })
20 .then(function(data){
21   console.log(data)
22 })
标准使用

但是上面的代码还存在着一些问题,如果第一个promise执行失败了,后面会影响到,所以如果 ,前面的 Promise 执行失败,我们不想让后续的Promise 操作被终止,可以为 每个 promise 指定 失败的回调

const fs = require('fs')
function getFileByPath(fpath){
  return new Promise(function (resolve,reject){
    fs.readFile(fpath,'utf-8',(err,dataStr)=>{
      if(err) return reject(err)
      resolve(dataStr)
    })
  })
}
getFileByPath('./files/2221.txt')
.then(function(data){
  console.log(data)
  //读取文件2
  return getFileByPath('./files/2.txt')
},function(err){
  if (err) console.log(err.message)
  return getFileByPath('./files/2.txt') 
})
.then(function( data){
  console.log(data)
  return getFileByPath('./files/3.txt')
})
.then(function(data){
  console.log(data)
})
console.log("assdsd")
View Code

执行结果 

75bbc66cd7cb5110803446bb2384c0b5.png

有时候,我们有这样的需求,个上面的需求刚好相反:如果 后续的Promise 执行,依赖于 前面 Promise 执行的结果,如果前面的失败了,则后面的就没有继续执行下去的意义了,此时,我们想要实现,一旦有报错,则立即终止所有 Promise的执行;
getFileByPath方法和上面一样

getFileByPath('./files/1.txt')
.then(function(data){
  console.log(data)
  //读取文件2
  return getFileByPath('./files/2.txt')
})
.then(function( data){
  console.log(data)
  return getFileByPath('./files/3.txt')
})
.then(function(data){
  console.log(data)
})
.catch(function(err){
  console.log("这是catch捕获到的异常:"+err.message)
})

执行结果 

ffd971dbd476a5891360c8fd6598490a.png
ptomise还有all和race方法

四、jQuery中Ajax使用ptomise

1、装包 npm init -y
2、cnpm i jquery -S
新建html文件,同时进行相应的配置

f24a17ea476ebdfa5849dc5eeb81d111.png
使用服务器启动,ctrl+shift+p调出命令栏,输express(也可以直接文件内右键选择“open with live server”)


PS:什么是Express,express是node.js的快速、非选择性、简约的web框架。使用express就可以轻松快速的创建强大的API。
Express安装步骤:
①  在VSC编辑器中选择打开自己的项目文件夹
②  Ctrl+shift+x  打开扩展商店搜索express并下载安装
③ Ctrl+` 打开调试控制台里的终端,输入  npm install express-generator -g
④ 创建一个自己命名的目录,输入: express 文件名(如果要在创建时使用ejs模板就在中间加一个-e。如:express -e 文件名)
⑤cd 文件名 进入到文件夹下 npm install
⑥npm start启动,打开localhost:3000,出现如下图3页面就代表安装成功 cd7759ad8cf7f78a812ceca1f4a6ea73.png

de6a2a01fc2fad1c536aafc22803bad4.png

 

d9ac8d8a282dea7c2cc48d8d31ed1c7b.png


回到正题
ctrl+shift+p调出命令栏,输express,选择如下图所示的选项 743e5e207358ea9bc9213d3c26b4d2df.png743e5e207358ea9bc9213d3c26b4d2df.png

跳转到如下页面,就ok了

5459816e5538d8312d9ede4f3a7e29e2.png
接着复制html的相对路径,粘贴到之前的路径上,可以看到效果

74f5dddf18afff4c1bf1cfe216c8fd34.png

高级操作:

 1 <input type="button" value="获取数据" id="btn">
 2     <script src="./node_modules//jquery/dist/jquery.min.js"></script>
 3     <script>
 4         //入口函数
 5         $(function(){
 6             $('#btn').on('click',function(){
 7                 $.ajax({
 8                     url:'./data.json',
 9                     type:'get',
10                     dataType:'json',
11                     // success:function(data){
12                     //     console.log(data)
13                     // }
14                 })
15                 .then(function(data){
16                     console.log(data)
17                 })
18             })
19         })
20     </script>
高级写法

 

posted @ 2019-10-31 19:27  小甜橘  阅读(255)  评论(0编辑  收藏  举报
返回顶部