读书笔记-你不知道的JS中-promise(2)
继续填坑
模式
考虑下面的代码:
function fn(x) {
//do something
return new Promise(function(resolve, reject) {
//调用resolve(..)和reject(...)
});
}
var p = fn(2);
new Promise(..)模式通常称为revealing constructor。传入函数会立即执行(不会像then(..)中的回调一样异步延迟),它有两个参数,分别为resolve和reject。这些是promise的决议函数。resolve通常标识完成,reject标识拒绝。
鸭子类型
如何判断一个对象是不是一个Promise?虽然promise是通过new Promise(..)创建的,但是无法通过instanceof Promise来检测,最主要的原因是promise可能来自其他的窗口,检查无法识别这样的Promise实例。
识别Promise的方法被定义为是否具有then方法。也就是说,任何对象和函数,如果有then(包括原型链上)方法,就认为是一个Promise对象。
逻辑大概如下:
if (
p !== null &&
(typeof p === 'object' || typeof p === 'function') &&
typeof p.then === 'function'
) {
//这是一个promise对象
}
Promise特点
1、对一个Promise调用then时,提供的回调永远会被异步调用。
2、只要promise被决议,提供给then的回调会被自动调用,永远返回一个值。
promise与竞态
虽然说一旦promise被决议,后续then方法的回调一定会被调用,但是决议本身未被执行,只能通过别的机制来强制执行:
//必须返回一个promise
function delay(time) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
reject('time out');
}, time);
});
}
//3秒内未决议就会被reject
Promise.race(p, delay(3000)).then(function() {
//success
}, function(err) {
//failed
})
Promise异常
考虑下面的代码:
var p = new Promise(function(resolve, reject) {
//异常
fo();
})
p.then(function(data) {
console.log(data);
}, function() {
//这个reject接受了异常 并又搞出了一个异常
foo();
}).then(function() { }, function() {
//这个reject处理了最后的异常
console.log(1);
});
可以看出,每一个then方法会返回一个promise,并且一旦决议就不会改变,异常会转接到下一个then的reject。
Promise的回调
看起来promise也是利用回调函数完成异步操作,但是有一些不同。
关于Promise.resolve(..)
如果向Promise.resolve(..)传递一个非Promise、非thenable(即有then方法的对象或函数)的立即值,就会得到一个用这个值填空的promise,相当于包装。
下面两种情况,p1和p2的行为是一样的:
var p1 = new Promise(function(resolve, reject) {
resolve(42);
});
var p2 = Promise.resolve(42);
console.log(p2); //Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: 42}
而如果向Promise.resolve(..)传递一个真正的Promise,就只会返回同一个promise。
var p1 = Promise.resolve(42);
var p2 = Promise.resolve(p1);
console.log(p1 === p2); //true
如果向Promise.resolve(..)传递了一个非Promise的thenable值,前者会试图展开这个值,而且展开过程会持续到提取出一个具体的非类Promise的最终值。
比如说:
var p = {
then: function(resolve, reject) {
resolve(42);
// reject('123');
}
};
p.then(function resolve(val) {
console.log(val);
}, function reject(err) {
console.log(err);
});
Promise.resolve(p); //打印42 得到一个Promise
Promise.resolve(..)可以接受任何thenable,将其解封为非thenable的值。从Promise.resolve(..)得到的肯定是一个Promise,是一个可信任的值。
将一个未知工具封装Promise并解析,可以这样:
Promise.resolve('tool').then(function(val) {
console.log(val);
});
这样,可以将所有未知封装为Promise,保证异步调用。
链式调用
可以把多个Promise连接到一起以表示一系列异步步骤:
1、每次调用then(..),它都会创建并返回一个新的Promise,我们可以将其链接起来。
2、不管从then(..)调用的完成回调返回的值是什么,都会被设置为被链接Promise。
不太懂啊:
var p = Promise.resolve(2);
var p2 = p.then(function(v) {
console.log(v); //
return v * 2;
});
p2.then(function(v) {
console.log(v); //
});
通过Promise.resolve对2进行封装,调用第一个then方法得到数据2。接着返回一个包含4的Promise封装对象,由调用then方法获取到4。
只要通过return和then方法,就能实现Promise链式调用。
Ajax案例
链式调用可以与ajax完美结合,如下例:
//假设存在方法ajax(url,callback)
function request(url) {
return new Promise(function(resolve, reject) {
//ajax的回调函数是promise的resolve()函数
ajax(url, resolve);
});
}
//异步请求返回数据data
request('http://...').then(function(data) {
//将返回的数据拼接到第二个url作为参数再次请求
return request('http://...?data=' + data);
}).then(function(data2) {
//得到最终数据
console.log(data2);
});
如果then方法参数未提供resolve或者reject,会有一个默认的函数生成,如下例:
Promise.resolve(2).then(
//function(v){
// return v;
//}
null,
function() {
console.log(1);
}).then(function(v) {
console.log(v); //
},
//默认错误处理函数
//function(err) {
// throw err;
//}
);
小结:1、调用Promise.resolve(..)与then(..)总会返回一个Promise。
2、决议后返回的值可以通过链式调用解决掉。
读书笔记-你不知道的JS中-promise(2)的更多相关文章
- 读书笔记-你不知道的JS中-promise
之前的笔记没保存没掉了,好气,重新写! 填坑-- 现在与将来 在单个JS文件中,程序由许多块组成,这些块有的现在执行,有的将来执行,最常见的块单位是函数. 程序中'将来'执行的部分并不一定在'现在'运 ...
- 读书笔记-你不知道的JS中-promise(3)
坑坑坑 关于术语:决议.完成以及拒绝. 首先观察Promise(..)构造器: var p = new Promise(function(x, y) { //x() 用于完成 //y() 用于拒绝 } ...
- 读书笔记-你不知道的JS中-函数生成器
这个坑比较深 可能写完我也看不懂(逃 ES6提供了一个新的函数特性,名字叫Generator,一开始看到,第一反应是函数指针?然而并不是,只是一个新的语法. 入门 简单来说,用法如下: functio ...
- 读书笔记-你不知道的JS上-对象
好想要对象··· 函数的调用位置不同会造成this绑定对象不同.但是对象到底是什么,为什么要绑定他们呢?(可以可以,我也不太懂) 语法 对象声明有两个形式: 1.字面量 => var obj = ...
- 读书笔记-你不知道的JS上-this
关于this 与静态词法作用域不用,this的指向动态绑定,在函数执行期间才能确定.感觉有点像C++的多态? var a = 1; var obj = { a: 2, fn: function() { ...
- 读书笔记-你不知道的JS上-函数作用域与块作用域
函数作用域 Javascript具有基于函数的作用域,每声明一个函数,都会产生一个对应的作用域. //全局作用域包含f1 function f1(a) { var b = 1; //f1作用域包含a, ...
- 读书笔记-你不知道的JS上-词法作用域
JS引擎 编译与执行 Javascript引擎会在词法分析和代码生成阶段对运行性能进行优化,包含对冗余元素进行优化(例如对语句在不影响结果的情况下进行重新组合). 对于Javascript来说,大部分 ...
- 读书笔记-你不知道的JS上-混入与原型
继承 mixin混合继承 function mixin(obj1, obj2) { for (var key in obj2) { //重复不复制 if (!(key in obj1)) { obj1 ...
- 读书笔记-你不知道的JS上-闭包与模块
闭包定义 当函数可以记住并访问所在的词法作用域时,就产生了闭包,即使函数是在当前词法作用域之外执行. 看一段最简单的闭包代码: function foo() { var a = 2; //闭包 fun ...
随机推荐
- GitHub新手使用教学(从安装到使用)
一.安装Git for Windows(又名msysgit) 下载地址: https://git-for-windows.github.io/ 在官方下载完后,安装到Windows Explore ...
- Maven(五)之Maven配置阿里云镜像飞快下jar包
用过Maven的人都知道Maven对于依赖的管理让我们程序员从此远离了自己去在项目中把需要的jar包导入到项目中,但是因为中央仓库是在国外的,所以在我们从中央仓库下载依赖的时候, 我们发现下载速度真的 ...
- thinkphp5.0无限极分类及格式化输出
首先我们来看数据表 从上图中可以发现,中国下有贵州,北京两个子节点,而北京有天安门一个子节点,纽约的子节点是"纽约的子类". 从pid为0看出,中国和纽约是顶级节点. 因为贵州的p ...
- 初学者一些常用的SQL语句(一)
一.数据库的创建create database 数据库名create database bbb二.表的创建 ***[]:可选项*** null:空值 not null 不为空***只有字符型能指定长度 ...
- AngularJS–service(服务)
点击查看AngularJS系列目录 转载请注明出处:http://www.cnblogs.com/leosx/ 服务 Angular的服务也是使用依赖注入(dependency injection ( ...
- 三、js的函数
三.函数 函数是定义一次但却可以调用或执行任意多次的一段JS代码.函数有时会有参数,即函数被调用时指定了值的局部变量.函数常常使用这些参数来计算一个返回值,这个值也成为函数调用表达式的值. 1.函数声 ...
- tomcat manager 的用户权限配置,及环境变量CATALINA_HOME的错位问题
因为tomcat的manager是管理其他项目的发布.删除等操作的管理项目,所以需要为其设置登陆用户和密码,以及用户相应的访问权限,配置如下: tomcat-users.xml需要添加如下内容: &l ...
- VBA /VB/VB中合成分散数据方法
公司用于项目号的合成,怕忘记,特此放上这里.若能帮助其它道友,善莫大焉. 比如:001,004,006,007,008,009,010 结果可以输出:001,004,006-010 逻辑:1.获得数据 ...
- Linux安装mysql-5.7.17
一.检查系统是否有自带安装MySQL 1.检查 [root@centos ~]# rpm -qa | grep -i mysql mysql-libs-5.1.71-1.el6.x86_64 2.卸载 ...
- 初学者易上手的SSH-struts2 01环境搭建
首先,SSH不是一个框架,而是多个框架(struts+spring+hibernate)的集成,是目前较流行的一种Web应用程序开源集成框架,用于构建灵活.易于扩展的多层Web应用程序. 集成SSH框 ...