zoukankan      html  css  js  c++  java
  • nodejs -Promise

    创建一个 readFile.js,读取三个文件abc的内容并输出到控制台

    var fs = require('fs')
    fs.readFile('./a.txt','utf-8',function (err,data) {
        if(err)
            throw err  //js语法,抛出异常,阻止程序执行,把错误打印到控制台
        console.log(data)  //将a.txt内容输出到控制台
    })
    
    fs.readFile('./b.txt','utf-8',function (err,data) {
        if(err)
            throw err
        console.log(data)
    })
    
    fs.readFile('./c.txt','utf-8',function (err,data) {
        if(err)
            throw err
        console.log(data)
    })

    一般来说文件内容少的会先输出,但不一定,由于读取文件是异步操作,所以无法保证abc的输出顺序

    若想abc按顺序输出,就需要将代码嵌套

    var fs = require('fs')
    fs.readFile('./a.txt','utf-8',function (err,data) {
        if(err)
            throw err
        console.log(data) //打印a.txt后再去读取b.txt
        fs.readFile('./b.txt','utf-8',function (err,data) {
            if(err)
                throw err
            console.log(data) //打印b.txt后再去读取c.txt
            fs.readFile('./c.txt','utf-8',function (err,data) {
                if(err)
                    throw err
                console.log(data)
            })
        })
    })

    像这样,在异步编程中,形成了回调函数嵌套,嵌套过多时被称为回调地狱(callback hell),此方式虽然能让异步操作按顺序执行,但十分不利于阅读和维护

     

    为了解决回调地狱嵌套编码方式带来的问题,ES6 新增了一个 API 叫 Promise,是一个构造函数

    Promise上有两个函数叫resolve(成功后的回调函数)和reject(失败后的回调函数)

    Promise原型里有一个then方法,所以只要是Promise创建的实例都可访问then方法

    Promise 容器存在一个异步任务,任务只有三种状态:Pending 为正在执行,Resolve 为已解决,Reiected 为失败

    示例

    var fs = require('fs')
    //Promise容器一旦创建就开始执行里面的代码
    var p = new Promise(function (resolve,reject) {
      fs.readFile('./a.txt','utf-8',function (err,data) {
         if(err){
            reject(err) //把容器的Pending状态变为Rejected
          }else{
             resolve(data) //把容器的Pending状态改为Resolve
          }
       })
    })
    
    //如何获取容器成功和失败的数据,就要用到p实例对象的then方法
    //then方法接收的第一个function就是容器中的resolved,第二个function是reject
    //两个function的参数就是上面容器resolve和reject传来的data和err.若resolve(123),则这里data就是123
    p.then(function (data) {
      console.log(data)
    },
    function (err) { consoel.log('文件读取失败',err) })

    Promise容器的创建不是异步的,但内部往往传入异步任务

     

    封装 Promise 版本的 readFile.js

    var fs = require('fs')
    function readFile(filePath) {
        //将Promise实例对象返回
        return new Promise(function (resolve,reject) {
            fs.readFile(filePath,'utf-8',function (err,data) {
                if(err){
                    reject(err)
                }else{
                    resolve(data)
                }
            })
        })
    }
    
    //因为返回的都是Promise的实例对象,所以可链式调用then
    readFile('./a.txt')
        .then(function (data) {
            console.log(data)  //data就是上面resolve传来的a文件的内容
            //然后将新的数据(err和data)通过resolve和reject传递给下一个then的function
            return readFile('./b.txt')
        })
        .then(function (data) {
            console.log(data)
            return readFile('./c.txt')
        })
        .then(function (data) {
            console.log(data)
        })

     

    封装 Promise 版本的 ajax 方法

    function get(url) {
        return new Promise(function (resolve, reject) {
            var xhr = new XMLHttpRequest()
            xhr.open('get', url)
            xhr.send()
            xhr.onload = function () {
                resolve(xhr.responseText) //成功则把获取的数据放resolve这个回调函数中
            }
            xhr.onerror = function (err) {
                reject(err) //失败则把失败信息放reject里
            }
        })
    }
    
    get('./a.txt')
        .then(function (data) {
            console.log(data)
            return get('./b.txt')
        })
        .then(function (data) {
            console.log(data)
            return get('./c.txt')
        })
        .then(function (data) {
            console.log(data)
        })

    如果前面的promise执行失败,不想让后续的promise操作被终止,可为每个promise指定失败的回调,然后在失败回调里return新的promise

    如果后续的promise执行依赖于前面的,前面的失败了,则后面的没有继续执行下去的意义时,可捕获异常

    get('./a.txt')
        .then(function (data) {
            console.log(data)
            return get('./b.txt')
        })
        .then(function (data) {
            console.log(data)
            return get('./c.txt')
        })
        .then(function (data) {
            console.log(data)
        })
        .catch(function(err){  //上面不要写失败回调
             console.log(err.message)   
        })

    如果前面有任何的promise执行失败则会立即终止所有promise执行并立刻进入catch中

    这就是捕获异常的两种方式,根据需求,可选择失败回调或catch

    模拟 jQuery 的 get 方法

    jq中的ajax()返回的是Promise实例,所以可直接点then()

    既能使用 Promise 也可以使用回调函数嵌套的方式,只需加多一个回调函数即可

    function get(url,callback) {
        return new Promise(function (resolve, reject) {
            var xhr = new XMLHttpRequest()
            xhr.open('get', url)
            xhr.send()
            xhr.onload = function () {
                callback(xhr.responseText)
                resolve(xhr.responseText) //成功则把获取的数据放resolve这个回调函数中
            }
            xhr.onerror = function (err) {
                callback(err)
                reject(err) //失败则把失败信息放reject里
            }
        })
    }
    
    /*get('./a.txt')
        .then(function (data) {
            console.log(data)
            return get('./b.txt')
        })
        .then(function (data) {
            console.log(data)
            return get('./c.txt')
        })
        .then(function (data) {
            console.log(data)
        })*/
    
    get('./a.txt',function (data) {
        console.log(data)
        get('./b.txt',function (data) {
            console.log(data)
            get('./c.txt',function (data) {
                console.log(data)
            })
        })
    })

     

    浏览器、Node、mongoose所有 API 都支持 Promise

  • 相关阅读:
    iOS开发--UIPickerView(选择器控件) 省份和城市的做法
    UITableView左滑设置更多的按钮
    UITableView的增,删,改例子
    UITableView的简单用法
    Block传值原理
    UIToolbar的简单用法
    用UIScrollView,UIPageControl来实现滚动视图。
    用UIPickerView来显示省和市
    如何设计好的UI控件
    UITextfield属性用法
  • 原文地址:https://www.cnblogs.com/Grani/p/9600700.html
Copyright © 2011-2022 走看看