深入理解ES6 011【学习笔记】

Promise与异步编程

因为执行引擎是单线程的,所以需要跟踪即将运行的代码,那些代码被放在一个任务队列中,每当一段代码准备执行时,都会被添加到任务队列中,每当引擎中的一段代码结束执行,事件循环会执行队列中的一下个任务。

Promise相当于异步操作结果占位符,它不会去订阅一个事件,也不会传递一个回调函数给目标函数,而是让函数返回一个Promise,就像这样

// readFile承诺在未来的某个刻完成
let promise = readFile('txx.txt')

Promise的生命周期

  • pending
  • fulfilled 成功
  • rejected 程序错误或一些其他原因

[[PromiseState]]内部属性被用来表示Promise的3种状态,这个属性不暴露在Promise对象上,所以不能以编程的方式检测Promise的状态,只有当Promise状态改变时,通过then()方法来采取特定的行为。所以Promise都有then方法,它接受两个参数,fulfilled和rejected时的两个回调函数

如果一个对象实现了上述的then方法,那这个对象我们就称之为thenable对象,所有的Promise对象都是thenable对象,但并非所有thenable对象都是Promise。

let promise = readFile("example.txt");
promise.then(function(contents){
  // 完成
},function(err){
  // 拒绝
})
promise.then(function(contents){
  // 完成
})

promise.then(null,function(err){
  // 拒绝
})
// catch等同于上面这种
promise.catch(function(err){
  // 拒绝
})

如果向Promise.resolve()方法或Promise.reject()方法传入一个Promise,那么这个Promise会被直接返回

Nodejs环境的拒绝处理

  • unhandledRejection
  • rejectionHandled
let rejected;
process.on("unhandledRejection",function(reason,promise){
  console.log(reason.message); // "Explosin"
  console.log(rejected === promise); // "Explosin"
})
rejected = Promise.reject(new Error('Explosin'))

串联Promise及链式返回值

let p1 = new Promise(function(resolve,reject){
  resolve(42)
})
p1.then(function(value){
  console.log(value)
  return value+1;
})
.then(function(value){
  console.log(value); // "43"
})

let p1 = new Promise(function(resolve,reject){
  reject(42)
})
p1.catch(function(value){
  console.log(value) // 42
  return value+1;
})
.then(function(value){
  console.log(value); // "43"
})

在Promsie链返回Promise

Promise.all()

只接受一个参数并返回一个Promise,该参数是一个含有多个受监视Promise的可迭代对象,只有当可迭代对象中所有Promise都被解决后返回的Promise才会被解决,只有当可迭代对象中所有Promise都完成后返回的promise才会被完成。只要有一个reject,就不用等所有的都完成就会被reject。

let p1 = new Promise(function(resolve,reject){
  resolve(42)
})
let p2 = new Promise(function(resolve,reject){
  reject(43)
})
let p3 = new Promise(function(resolve,reject){
  resolve(44)
})
let p4 =  Promise.all([p1,p2,p3])
p4.catch(function(value){
  console.log(Array.isArray(value)); //false
  console.log(value); // 43
})

Promise.race()

只要有一个resolve,不用等所有的都被完成。一旦数组中的某个Promise被完成,Promise.race()方法也会像Promise.all()方法一样返回一个特定的Promise

Promise继承

class MyPromise extends Promise {
  // 使用默认的构造函数

  success(resolove,reject){
    return this.then(resolove,reject)
  }
  failure(reject){
    return this.catch(reject)
  }
}
let promise = new MyPromise(function(resolve,reject){
  resolve(42)
})
promise.success(function(value){
  console.log(value) // 42
})
.failure(function(value){
  console.log(value)
})

基于Promise的异步任务执行

改造之前的文件读取功能。只要每个异步操作都返回Promise,就可以极大地简化并能用化这个过程。以Promise作为通用接口用于所有异步代码可以简化任务执行器。

let fs = require("fs");

function run(taskDef){
  // 创建迭代器
  let task = taskDef()

  // 开始执行任务
  let result = task.next();

  // 递归函数遍历
  (function step(){
    // 如果有更多任务要做
    if(!result.done){
      // 用一个Promise来解决会简化问题
      let promise = Promise.resolove(result.value);
      promise.then(function(value){
        result = task.next(value);
        step()
      })
      .catch(function(error){
        result = task.throw(error);
        step();
      })
    }

  }())
}
// 定义一个可用于任务执行器的函数
function readFile(filename){
  return new Promise(function(resolove,reject){
    fs.readFile(filename,function(err,contents){
      if(err){
        reject(err);
      } else {
        resolove(contents)
      }
    })
  })
}

// 执行一个任务
run(function *(){
  let contents = yield readFile("config.json");
  doSomethingWith(contents);
  console.log("Done")
})

主题测试文章,只做测试使用。发布者:Walker,转转请注明出处:https://walker-learn.xyz/archives/4337

(0)
Walker的头像Walker
上一篇 2025年11月25日 17:00
下一篇 2025年11月24日 00:00

相关推荐

  • Go工程师体系课 018【学习笔记】

    API 网关与持续部署入门(Kong & Jenkins) 对应资料目录《第 2 章 Jenkins 入门》《第 3 章 通过 Jenkins 部署服务》,整理 Kong 与 Jenkins 在企业级持续交付中的实战路径。即便零基础,也能顺着步骤搭建出自己的网关 + 持续部署流水线。 课前导览:什么是 API 网关 API 网关位于客户端与后端微服务…

    个人 2025年11月25日
    28600
  • 深入理解ES6 013【学习笔记】

    用模块封装代码 javascript用“共享一切”的方法加载代码,这是该语言中最容易出错且另人感到困惑的地方。其他语言使用诸如包这样的概念来定义代码作用域。在es6以前,在应用程序的每一个js中定义的一切都共享一个全局作用域。随着web应用程序变得更加复杂,js代码的使用量也开始增长,这一做法会引起问题,如命名冲突和安全问题。es6的一个目标是解决作用域问题…

    个人 2025年3月8日
    1.3K00
  • 深入理解ES6 008【学习笔记】

    迭代器(Iterator)和生成器(Generator) 这个新特性对于高效的数据处理而言是不可或缺的,你也会发现在语言的其他特性中也都有迭代器的身影:新的for-of循环、展开运算符(...)、甚至连异步编程都可以使用迭代器。 迭代器是一种特殊的对象,它具有一些专门为迭代过程设计的专有接口,所有的迭代器对象都有一个next()方法,每次调用都返回一个结果对…

    个人 2025年3月8日
    1.2K00
  • 深入理解ES6 006【学习笔记】

    Symbol和Symbol属性 第6种原始数据类型:Symbol。私有名称原本是为了让开发者们创建非字符串属性名称而设计的,但是一般的技术无法检测这些属性的私有名称 创建Symbol let firstName = Symbol(); let person = {} person[firstName] = "Nicholas"; cons…

    个人 2025年3月8日
    1.4K00
  • Go工程师体系课 014【学习笔记】

    rocketmq 快速入门 去我们的各种配置(podman)看是怎么安装的 概念介绍 RocketMQ 是阿里开源、Apache 顶级项目的分布式消息中间件,核心组件: NameServer:服务发现与路由 Broker:消息存储、投递、拉取 Producer:消息生产者(发送消息) Consumer:消息消费者(订阅并消费消息) Topic/Tag:主题/…

    个人 2025年11月25日
    28800
简体中文 繁体中文 English