前言:该问题是由于看到fetch的then方法的使用,产生的疑问,在深入了解并记录对promise的个人理解

首先看一下fetch请求使用案例:

案例效果:点击页面按钮,请求当前目录下的arr.txt里面的内容

疑问地方:

1. fetch为什么可以使用then?(个人理解then方法是定义在原型对象Promise.prototype上的)

2. 为什么使用两次then才能取出数据?(重点疑惑是这里,疑惑第二个then没有进行其他操作,只是将上一个then的返回值进行输出,就可以获取到arr.txt的数据)

let oBtn = document.getElementById("btn1");
oBtn.onclick = function(){
let url = "arr.txt";
//let url = "json.txt";
fetch(url).then(res=>{
/*
res.text 返回的是一个纯文本 是一个promise对象
res.json 返回的是一个对象(json/array) 是一个promise对象
response是只能被读取一次的,console.log取一次,return取一次,会报错
*/
let resdata = res.json();
console.log(,resdata);
//打印:[[PromiseStatus]]: "resolved"
//return res.text();
return resdata; //返回值是一个新的promise对象,状态为resolved,所以执行then
}).then(data=>{ //上一个then返回值是Promise对象(即有异步操作),等待该Promise对象的状态发生变化,then才会被调用
console.log(1,data)},data2=>{
console.log(2,data2)}
).catch(err=>{
console.log(,err);
}); };

 所以去查询了then的用法,查询到阮一峰写了关于promise的文章http://es6.ruanyifeng.com/?search=fecth&x=0&y=0#docs/promise,里面介绍到promise和then的具体用法:

看到一个案例:任务执行顺序问题:(中间插曲)

let promise = new Promise(function(resolve, reject) {
console.log('Promise');
resolve();
}); promise.then(function() {
console.log('resolved.');
}); console.log('Hi!'); // Promise
// Hi!
// resolved

解释:

1.  Promise 新建后立即执行,所以首先输出的是Promise

2. 当请求到数据后,执行resolve方法,改变promise状态为resolved,使then方法执行第一个回调函数,第一个函数参数为resolve传递出来的数据,将在当前脚本所有同步任务执行完才会执行,所以resolved最后输出。为啥最后执行呢?

  我又去查询下JavaScript 运行机制详解:也是理解与阮一峰的:

  理解出一条:先执行主线程(同步任务放置在主线程),主线程执行完,系统去读取任务队列中(异步任务放置在任务队列),js的运行机制是这样设定的。嗯,没毛病

3. 意思就是resolve是异步任务,放置在任务队列中,console.log("HI")  是同步任务,放置在主程序中,当主程序中的执行完,才会去查看任务队列。

执行结果:

// Promise
// Hi!
// resolved 继续介绍then用法:

  Promise 实例具有then方法,也就是说,then方法是定义在原型对象Promise.prototype上的。它的作用是为 Promise 实例添加状态改变时的回调函数。前面说过,then方法的第一个参数是resolved状态的回调函数,第二个参数(可选)是rejected状态的回调函数。

  then方法返回的是一个新的Promise实例(注意,不是原来那个Promise实例)。因此可以采用链式写法,即then方法后面再调用另一个then方法

  这句话跟fetch的用法是一样的由于then的返回值是一个promise实例,可以采用的是链式写法,

还是但是fetch和promise还是没啥关系?
当我又看到一个案例:为啥getJSON()这个可以使用then,应该是new promise才可以使用then吗?我才明白getJSON是封装的一个函数,返回值是new promise,所以执行getJSON()可以使用then的方法
getJSON("/posts.json").then(function(json) {
return json.post;
}).then(function(post) {
// ...
});
到现在才明白fetch()其实就是封装了的promise的函数,返回值是promise的实例,所以才能调用then用法,所以说,fetch()其实就是promise的实例。
回到最初的疑问?

1. fetch为什么可以使用then?(个人理解then方法是定义在原型对象Promise.prototype上的)

2. 为什么使用两次then才能取出数据?(重点疑惑是这里,疑惑第二个then没有进行其他操作,只是将上一个then的返回值进行输出,就可以获取到arr.txt的数据)

为什么使用两次then才能正常取出数据?我将最初的案例运行:查看第一个then的返回值是啥?
let oBtn = document.getElementById("btn1");
oBtn.onclick = function(){
let url = "arr.txt";
//let url = "json.txt"; fetch(url).then(res=>{
/*
res.text 返回的是一个纯文本 是一个promise对象
res.json 返回的是一个对象(json/array) 是一个promise对象
response是只能被读取一次的,console.log取一次,return取一次,会报错
*/
let resdata = res.json();
console.log(,resdata);
//打印:[[PromiseStatus]]: "resolved"
//return res.text();
return resdata; //返回值是一个新的promise对象,状态为resolved,所以执行then

         // Promise
         // __proto__
         //:
         //Promise
         //[[PromiseStatus]]:"resolved"
         //[[PromiseValue]]:Array[3]

        }).then(data=>{ //上一个then返回值是Promise对象(即有异步操作),等待该Promise对象的状态发生变化,then才会被调用
console.log(,data)},data2=>{
console.log(,data2)}
).catch(err=>{
console.log(,err);
}); };
解释两次then用法:

第一次then用法:then是根据promise的状态变化而执行的回调函数,promise的状态变化由resolve()函数决定(取到数据执行resolve),then的参数为resolve函数传递出来的数据,
直接输出res是一个对象不是我们需要的数据,使用res.json()或者res.test()获取到我们需要的数据。
res.json()/res.text()获取到的是一个新的promise实例,arr.txt的值在[[[PromiseValue]]里面,但是直接取是取不出来的。没有方法取出来,
Promise的设计文档中说了,[[PromiseValue]]是个内部变量,外部无法得到,只能在then中获取。所以就会用到第二次then了
第二次then用法:就是怎么将[[[PromiseValue]]里面的数据取出来
现在就重点理解下[[[PromiseValue]]这个怎么获取到的?
代码中的resolve()就是说明resolve内部是怎么运行的,改变promise的状态,给PromiseValue复制,
/* 用于描述思维的代码 */
executor(resolve, reject) {
...
resolve(value);
...
}
...
resolve(value) {
PromiseStatus = 'fulfilled';
PromiseValue = value;
...
// 接着调用回调链中的回调函数
}
这句话解决了第二个then的用法:
onFulfilled(value)和onRejected(reason):参数value和reason的实参都是PromiseValue。这句话是说then的回调函数参数使用的都是PromiseValue,所以直接输出就会获取到PromiseValue的值 这里有一点值得注意:第一个then 的return返回值是一个promise实例对象,所以回调链转交给了新的实例对象,第二个then的回调函数参数为为PromiseValue的值,当返回值不是对象时,返回值是数据类型时,会将该返回值
赋值给PromiseValue,供下次的then函数使用
如果onFulfilled(value)和onRejected(reason)这两个回调函数中return返回值不是一个Promise的对象,(then)
那么这个返回值会被赋给PromiseValue,并在下一个then()的onFulfilled(value)和onRejected(reason)中做为实参使用。
但如果这个返回值是一个Promise的对象,那么剩下的由then()构造的回调链会转交给新的Promise对象并完成调用。
回调链是啥??
then(onFulfilled, onRejected):这个方法实际上是把onFulfilled()函数和onRejected()函数添加到Promise对象的回调链中。
回调链就像一个由函数组构成的队列,每一组函数都是由至少一个函数构成(onFulfilled() 或者 onRejected() 或者 onFulfilled() 和 onRejected())。
当resolve()或者reject()方法执行的时候,回调链中的回调函数会根据PromiseStatus的状态情况而被依次调用。


结合promise对原生fetch的两个then用法理解的更多相关文章

  1. 基于Promise规范的fetch API的使用

    基于Promise规范的fetch API的使用 fetch的使用 作用:fetch 这个API,是专门用来发起Ajax请求的: fetch 是由原生 JS 提供的 API ,专门用来取代 XHR 这 ...

  2. 20190313 org.apache.commons.lang3.builder.EqualsBuilder的两种典型用法

    org.apache.commons.lang3.builder.EqualsBuilder的两种典型用法 public boolean equals(Object obj) { if (obj == ...

  3. 第五节: 前后端交互之Promise用法和Fetch用法

    一. Promise相关 1.说明 主要解决异步深层嵌套的问题,promise 提供了简洁的API 使得异步操作更加容易 . 2.入门使用 我们使用new来构建一个Promise Promise的构造 ...

  4. 封装 原生 fetch

    1, 简介 fetch方法是 Fetch API的一个方法,提供了一种简单.合理的方式来跨网络异步获取资源. 与原来的XMLHttpRequest比较,fetch更容易与其他的技术结合:比如servi ...

  5. vue实践---vue结合 promise 封装原生ajax

    有时候不想使用axios这样的外部依赖,想自己封装ajax,这里有两种方法 方法一,在单个页面内使用 封装的代码如下: beforeCreate () { this.$http = (() => ...

  6. 谈谈 Promise 以及实现 Fetch 的思路

    Promise 是异步编程的一种解决方案. Promise /** * 属性 */ Promise.length Promise.prototype /** * 方法 */ Promise.all(i ...

  7. 不使用spring的情况下原生java代码两种方式操作mongodb数据库

    由于更改了mongodb3.0数据库的密码,导致这几天storm组对数据进行处理的时候,一直在报mongodb数据库连接不上的异常.   主要原因实际上是和mongodb本身无关的,因为他们改的是配置 ...

  8. uni-app强大的前端框架,h5,原生app(两大系统),微信小程序

    最近发现一款强大的前端框架,它叫uni-app 这是一款通用的框架可以打包app,h5,微信小程序, 说说要弄这个工具需要会那些技能吧, 要熟悉vue,微信小程序.这样这个框架用的就是很快上手了 模块 ...

  9. java interface的两个经典用法

    1.Java多态接口动态加载实例 编写一个通用程序,用来计算没一种交通工具运行1000公里所需的时间,已知每种交通工具的参数都为3个整数A.B.C的表达式.现有两种工具:Car和Plane,其中Car ...

随机推荐

  1. JDK源码分析 – ArrayList

    ArrayList类的申明 ArrayList是一个支持泛型的,底层通过数组实现的一个可以存任意类型的数据结构,源码中的定义如下: public class ArrayList<E> ex ...

  2. STL--heap概述:make_heap,sort_heap,pop_heap,push_heap

    heap并不属于STL容器组件,它分为 max heap 和min heap,在缺省情况下,max-heap是优先队列(priority queue)的底层实现机制. 而这个实现机制中的max-hea ...

  3. MONyog-数据库性能监控工具

    一.安装步骤 较为简单,网上可以搜索到,此处不做详细说明. 二.使用图解 此处介绍监控数据库连接量.并发量.吞吐量.响应时间等功能 1.设置连接需要监控的数据库 打开:http://127.0.0.1 ...

  4. 第54天:原生js实现轮播图效果

    一.轮播图的原理: 一系列的大小相等的图片平铺,利用CSS布局只显示一张图片,其余隐藏.通过计算偏移量利用定时器实现自动播放,或通过手动点击事件切换图片. 二.Html布局 首先父容器containe ...

  5. C++中Set的使用

    /* #include <string> // 使用 string 类时须包含这个文件 #include <iostream> // 这个就加上去吧.c++的输入和输出. us ...

  6. springMVC+spring+mybatis搭建最近

    一:概述SSM框架在项目开发中经常使用到,相比于SSH框架,它在仅几年的开发中运用的更加广泛. Spring作为一个轻量级的框架,有很多的拓展功能,最主要的我们一般项目使用的就是IOC和AOP. Sp ...

  7. BZOJ3435 & 洛谷3920 & UOJ55:[WC2014]紫荆花之恋

    https://www.lydsy.com/JudgeOnline/problem.php?id=3435 https://www.luogu.org/problemnew/show/P3920 ht ...

  8. [学习笔记]2-SAT 问题

    (本文语言不通,细节省略较多,不适合初学者学习) 解决一类简单的sat问题. 每个变量有0/1两种取值,m个限制条件都可以转化成形如:若x为0/1则y为0/1等等(x可以等于y) 具体: 每个变量拆成 ...

  9. 【树状数组】【P2345】 奶牛集会

    传送门 Description 约翰的\(N\)头奶牛每年都会参加"哞哞大会".哞哞大会是奶牛界的盛事.集会上的活动很多,比如堆干草,跨栅栏,摸牛仔的屁股等等.它们参加活动时会聚在 ...

  10. 【DP优化】【P1430】序列取数

    传送门 Description 给定一个长为n的整数序列,由A和B轮流取数(A先取).每个人可从序列的左端或右端取若干个数(至少一个),但不能两端都取.所有数都被取走后,两人分别统计所取数的和作为各自 ...