进击Node.js基础(二)promise

一.Promise

JS动画settimeout,setinterval,requestAnimationFrame,promise

npm install bluebird

 Javascript的特点是异步,Javascript不能等待,如果你实现某件需要等待的事情,你不能停在那里一直等待结果回来,相反,底线是使用回调callback:你定义一个函数,这个函数只有等到结果可用时才能被调用。

 这种回调模型对于好的代码组织是没有问题的,但是也可以通过从原始回调切换到promise解决很多问题,将promise看成是一个标准的数据容器,这样会简化你的代码组织,可以成为基于promise的架构。

什么是Promise?

 一个promise是一个带有".then()"方法的对象,其代表的是一个操作的结果可能还没有或不知道,无论谁访问这个对象,都能够使用".then()"方法加入回调等待操作出现成功结果或失败时的提醒通知,。

 那么为什么这样做好处优于回调呢?标准的回调模式在我们处理请求时需要同时提供回调函数:

request(url, function(error, response) {
  // handle success or error.
});
doSomethingElse();
 很不幸,这段代码意味着这个request函数并不知道它自己什么时候能够完成,当然也没有必要,我们最终通过回调传递结果。这会导致多个回调形成了嵌套回调,或者称为回调陷阱。

queryTheDatabase(query, function(error, result) {
  request(url, function(error, response) {
    doSomethingElse(response, function(error, result) {
      doAnotherThing(result, function(error, result) {
        request(anotherUrl, function(error, response) {
          ...
        });
      });
    });
  });
});
 Promise能够解决这种问题,允许低层代码创建一个request然后返回一个对象,其代表着未完成的操作,让调用者去决定应该加入什么回调。

Promise是什么?

 promise是一个异步编程的抽象,它是一个返回值或抛出exception的代理对象,一般promise对象都有一个then方法,这个then方法是我们如何获得返回值(成功实现承诺的结果值,称为fulfillment)或抛出exception(拒绝承诺的理由,称为rejection),then是用两个可选的回调作为参数,我们可以称为onFulfilled和OnRejected:

var promise = doSomethingAync()
promise.then(onFulfilled, onRejected)

 当这个promise被解决了,也就是异步过程完成后,onFulfilled和OnRejected中任何一个将被调用,

 因此,一个promise有下面三个不同状态:

pending待承诺 - promise初始状态
fulfilled实现承诺 - 一个承诺成功实现状态
rejected拒绝承诺 - 一个承诺失败的状态
 以读取文件为案例,下面是使用回调实现读取文件后应该做什么事情(输出打印):

readFile(function (err, data) {
  if (err) return console.error(err)
  console.log(data)
})
 如果我们的readFile函数返回一个promise,那么我们可以如下实现同样的逻辑(输出打印):

var promise = readFile()
promise.then(console.log, console.error)

 这里我们有了一个值promise代表的是异步操作,我们能够一直传递这个值promise,任何人访问这个值都能够使用then来消费使用它,无论这个值代表的异步操作是否完成或没有完成,我们也能保证异步的结果不会改变,因为这个promise代表的异步操作只会执行一次,状态是要么fulfilled要么是rejected。

理解Promise

 Promise可能是不同于日常直觉,为了理解它,一些重要原理必须记牢: .then()总是返回一个新的promise.,如下面代码:

var promise = readFile()
var promise2 = promise.then(readAnotherFile, console.error)

 这里then的参数readAnotherFile, console.error是代表异步操作成功后的动作onFulfilled或失败后的动作OnRejected,也就是说,读取文件成功后执行readAnotherFile函数,否则失败打印记录错误。这种实现是两个中只有一种可能。

 我们再看下面上述代码如下:

var promise = readFile()
var promise2 = promise.then(function (data) {
  return readAnotherFile() // 如果readFile成功,执行readAnotherFile
}, function (err) {
  console.error(err) // 如果readFile不成功,记录,但是还是执行readAnotherFile
  return readAnotherFile()
})
promise2.then(console.log, console.error) // readAnotherFile函数的执行结果
 因为then返回一个promise,它意味着promise能够被chain串行链条花,这样能避免回调地狱:

readFile()
  .then(readAnotherFile)
  .then(doSomethingElse)
  .then(...)
 Promise法则有两部分必须分离:

 (1).then()总是返回一个新的promise,每次你调用它,它不管回调做什么,因为.then()在回调被调用之前已经给了你一个承诺promise,回调的行为只影响承诺promise的实施,如果回调返回一个值,那么promise将使用那个值,如果这个值是一个promise,返回这个promise实施后的值给这个值,如果回调抛出错误,promise将拒绝错误。

 (2)被.then()返回的promise是一个新的promise,它不同于那些.then()被调用的promise,promise长长的链条有时会好些隐藏这个事实,不管如何,每次.then()调用都会产生一个新的promise,这里必须注意的是你真正需要考虑的是你最后调用.then()可能代表失败,那么如果你不捕获这种失败,那么容易导致你的错误exception消失。

 一些人认为.then()串联链条调用很类似fluent风格,但是长长的promise链条会让人迷惑,最后切分为一个个有意义的函数:

function getTasks() {
  return $http.get(‘http://example.com/api/v1/tasks‘)
    .then(function(response) {
      return response.data;
    });
}

function getMyTasks() {
  return getTasks()
    .then(function(tasks) {
      return filterTasks(tasks, {
        owner: user.username
      });
    });
}
 在这个例子中,两个函数各自获得一个promise,携带了一个回调函数。

有趣的Promise

 同样的promise能够接受任何数目的回调,当一个Promise被解决实施后,其中所有回调函数都会被调用,此外,一个promise在被解决实施后,甚至可以接受一个新的回调,这些回调完成能以正常方式被调用,这就允许我们使用回调实现简单形式的缓存:

var tasksPromise;
function getTasks() {
  taskPromise = taskPromise || getTasksFromTheServer();
  return taskPromise;
}
 这个案例中,getTasks()函数可以被任意次数调用,它总是返回铜牙的promise,其中函数getTasksFromTheServer()却只是被调用一次。
时间: 2024-10-09 08:47:16

进击Node.js基础(二)promise的相关文章

进击Node.js基础(二)

一.一个牛逼闪闪的知识点Promise npm install bluebird 二.牛逼闪闪的Promise只需三点1.Promise是JS针对异步操作场景的解决方案 针对异步的场景,业界有很多解决方案,如回调.事件机制 Promise是一个对象,同时它也一种规范,针对异步操作约定了统一的接口,表示一个异步操作的最终结果以同步的方式来写代码,执行的操作是异步的,但是又保证程序的执行顺序是同步的. 原本是社区的一个规范的构想,被加入到ES6的语言标准里面,比如Chrom,Firefox浏览器已对

进击Node.js基础(一)

一.前言 1:Node.js本质上是用chrome浏览器 v8引擎 使用c++编写的JS运行环境 2:相比于JS没有浏览器安全级的限制,额外提供了一些系统级的API:文件读写,进程管理,网络通信等. 3:有很多借助NODE.JS完成的项目如appjs跨平台桌面应用,Jade和node.js组合使用便捷管理后台html模板,grunt自动化运行工具,express.js 4:nodejs.org,npmjs.com模块社区,github,stackoverflow 5:gitbash:类似cmd,

10慕课网《进击Node.js基础(一)》初识promise

首先用嘴简单的方式实现一个动画效果 <!doctype> <html> <head> <title>Promise animation</title> <style type="text/css"> .ball { width: 40px; height: 40px; border-radius: 20px; } .ball1 { background: red; } .ball2 { background: ye

04慕课网《进击Node.js基础(一)》HTTP讲解

HTTP:通信协议 流程概述: http客户端发起请求,创建端口默认8080 http服务器在端口监听客户端请求 http服务器向客户端返回状态和内容 稍微详细解析: 1.域名解析:浏览器搜素自身的DNS缓冲,查看是否有被请求的域名所定义的IP,缓冲1分钟 ## 谷歌浏览器输入:chrome://net-internals/#dns 2.搜索操作系统自身的DNS缓冲(浏览器无缓冲或失效) 3.读取本地的HOST文件 C:\Windows\System32\drivers\etc 4.浏览器发起

05慕课网《进击Node.js基础(一)》HTTP概念进阶

HTTP模块介绍 支持http协议的更多特性 不缓存请求和响应 API比较底层处理流相关,信息解析 HTTP相关概念 回调 将函数作为参数传到执行函数中,参数函数在执行函数中嵌套执行 function learn(something){ console.log(something); } function we(callback,something){ something+=' is cool' callback(something) } //具名函数 we(learn,'Nodejs') //

08慕课网《进击Node.js基础(一)》事件events

引用events模块中的EventEmitter 事件的监听和发射 相同的事件发射数量有限,可以通过setMaxListeners设置峰值 var EventEmitter = require('events').EventEmitter var life = new EventEmitter() //加不加都没有报警告 //life.setMaxListeners(10) life.on('clickEvent',function(who){ console.log('给' + who + '

11慕课网《进击Node.js基础(一)》Buffer和Stream

Buffer (logo.png) 以下代码读取logo.png为buffer类型 然后将buffer转化为string 可以将字符串配置: data:image/png;Base64,Buffer.toString() var fs = require('fs') fs.readFile('logo.png',function(err,origin_buffer){ console.log('origin_buffer是否Buffer格式:'+Buffer.isBuffer(origin_bu

node.js基础模块http、网页分析工具cherrio实现爬虫

node.js基础模块http.网页分析工具cherrio实现爬虫 一.前言      说是爬虫初探,其实并没有用到爬虫相关第三方类库,主要用了node.js基础模块http.网页分析工具cherrio. 使用http直接获取url路径对应网页资源,然后使用cherrio分析. 这里我主要学习过的案例自己敲了一遍,加深理解.在coding的过程中,我第一次把jq获取后的对象直接用forEach遍历,直接报错,是因为jq没有对应的这个方法,只有js数组可以调用. 二.知识点    ①:supera

NodeJs&gt;-------&gt;&gt;第三章:Node.js基础知识

第三章:Node.js基础知识 一:Node.js中的控制台 1:console.log.console.info  方法 1 console.log("this is a test string."); 1 node app1.js 1> info.log 1 console.log("This is a test String ."); 2 3 //从第二个参数开始,依序输出所有的字符串 4 console.log("%s","