js异步原理与 Promise
一、Javascript的异步原理
javascript 是单线程语言,所以同一时间只执行一个运算。但有些方法是不能瞬间完成或不可预知何时完成的(如网络请求、settimeout等),为了让它们不对后续的运算产生阻塞,就需要用到异步操作。HTML5提出的Web Worker 允许在后台创建 JavaScript子线程,也可以用来防止阻塞,只是实现方对复杂、浏览器支持性不佳。
javascript 的异步就是通过回调函数实现的。异步事件被触发时,即意味着对应的回调函数被执行。
javascript 引擎会基于事件轮询(event-loop)机制捋出一个任务队列:执行所有的同步操作;过程中若遇到异步操作,就将异步事件排入另一个队列;待所有同步操作完成时,开始监听异步事件队列,等待事件触发并执行。
setTimeout(function() {
console.log("a");
}, 0); // 这里是异步,0延迟不代表立即执行
var sum=0;
for (var i = 0; i < 1000000; i++) {
sum += i;
};
console.log("b" + sum);
如上示例,会先打印出b,再打印a。
二、Promise规范
Promise的目的是为了给异步编程提供统一接口,实现了回调函数的链式写法。目前Promise已经纳入了ES6标准,逐渐成为回调函数的写法规范。
- 三种状态:等待(pending)、已完成(fulfilled)、已拒绝(rejected)
- 一个promise的状态只可能从“等待”转到“完成”态或者“拒绝”态
- promise必须实现
then方法,并接受两个参数,分别是成功和失败后的回调
Promise规范了Resolve、Reject、Then、Catch、All等方法。 Resolve和Reject分别指代异步操作执行成功和失败时对应执行的回掉函数,它们以参数的形式传入Then方法中。Catch用以捕获错误,All方法可以接收一个元素为 Promise 对象的数组作为参数,当这个数组里面所有的 Promise 对象都变为 resolve 时,该方法才会返回。ES6的Promise基本定义方法如下:
var myPromise = new Promise(function(resolve, reject){
//做一些异步操作
setTimeout(function(){
console.log('执行完成');
resolve('数据传递');
}, 2000);
});
myPromise.then(function(data){
//数据处理代码...
console.log(data);
});
在创建myPromise的时候,向Promise构造函数传递了两个参数resolve和reject,此时这两个没有实际意义;在执行then的时候,才知道resolve具体是什么函数。上例的then只传了一个函数进来,默认为resolve;若传递了两个函数,则第二个即为reject。myPromise中定义了传给回调函数的数据,上例中“数据传递”即传给了resolve回调函数。
写入Promise中的异步操作是会立即进入事件队列的,上例中,即使不写myPromise.then(),控制台依旧会打印出“执行完成”。在实际使用中,更科学的控制方式是将Promise对象的定义写入一个函数中,并return这个对象。
function test(){
var myPromise = new Promise(function(resolve, reject){
setTimeout(function(){
console.log('执行完成');
resolve('数据传递');
}, 2000);
});
return myPromise;
}
test().then(function(data){
console.log(data);
});
then的链式调用能够简化层层回调的写法,避免回调地狱。Promise的精髓是“状态”,用维护状态、传递状态的方式来使得回调函数能够及时调用,它比传递callback函数要简单、灵活的多。在then的resolve方法中返回一个新的Promise对象或者一个数据,都可以后接新的then()。
function test(){
var promise1 = new Promise(function(resolve, reject){
setTimeout(function(){
console.log('第一个Promise执行完成');
resolve('传递给第一个resolve的数据');
}, 2000);
});
return promise1;
}
test().then(function(val){
console.log('进入第一个then');
console.log(val);
var promise2 = new Promise(function(resolve, reject){
setTimeout(function(){
console.log('第一个then执行完成');
resolve('传递给第二个resolve的数据');
}, 2000);
})
return promise2; //返回一个新的Promise对象
}).then(function(val){
console.log('进入第二个then');
console.log(val);
return("传递给第三个resolve的数据") //返回一个值,也可以接then(),其值将被当作参数传递给resolve
}).then(function(val){
console.log("进入第三个then");
console.log(val);
})
三、Promise的执行优先级
setTimeout(()=>{
console.log("setTimeout")
},0)
new Promise((resolve,reject)=>{
console.log("in promise")
resolve("promise resolve");
}).then((data)=>{
console.log(data)
})
console.log("sync")
上面代码的执行结果为:先后输出 in promise、sync、promise resolve、setTimeout

首先要理解,Promise回掉函数的执行是异步的,但Promise本身的定义是同步执行的,所以按照顺序,in promise会在sync前输出。
其次,Promise回调的优先级是高于setTimeout等异步操作的,所以promise resolve会先于seTtimeout输出。浏览器会将promise callbacks加入到同步事件队列的末尾,而不是异步事件的队列。
js异步原理与 Promise的更多相关文章
- JS异步编程 (2) - Promise、Generator、async/await
JS异步编程 (2) - Promise.Generator.async/await 上篇文章我们讲了下JS异步编程的相关知识,比如什么是异步,为什么要使用异步编程以及在浏览器中JS如何实现异步的.最 ...
- js异步原理
javascript引擎 javascript引擎执行时单线程的,如果有一个任务被阻塞,整个浏览器就会处于假死状态 那么遇到这种情况,又在单线程的情况下,不能像java之类的语言创建多几个线程来处理, ...
- 深入理解JS异步编程三(promise)
jQuery 原本写一个小动画我们可能是这样的 $('.animateEle').animate({ opacity:'.5' }, 4000,function(){ $('.animateEle2' ...
- 异步编程之Promise(2):探究原理
异步编程系列教程: (翻译)异步编程之Promise(1)--初见魅力 异步编程之Promise(2):探究原理 异步编程之Promise(3):拓展进阶 异步编程之Generator(1)--领略魅 ...
- JS 异步系列 —— Promise 札记
Promise 研究 Promise 的动机大体有以下几点: 对其 api 的不熟悉以及对实现机制的好奇; 很多库(比如 fetch)是基于 Promise 封装的,那么要了解这些库的前置条件得先熟悉 ...
- node.js异步编程解决方案之Promise用法
node.js异步编程解决方案之Promise var dbBase = require('../db/db_base'); var school_info_db = require('../db/s ...
- 一个例子读懂 JS 异步编程: Callback / Promise / Generator / Async
JS异步编程实践理解 回顾JS异步编程方法的发展,主要有以下几种方式: Callback Promise Generator Async 需求 显示购物车商品列表的页面,用户可以勾选想要删除商品(单选 ...
- generator和promise配合解决js异步地狱问题
为何要使用generator函数和promise? js的异步地狱一直是困扰前端程序员的一个头疼的问题 比如说我要获取还有列表,一般来说会使用ajax来获取 $.ajax(...等等,function ...
- js 深入原理讲解系列-Promise
js 深入原理讲解系列-Promise 能看懂这一题你就掌握了 js Promise 的核心原理 不要专业的术语,说人话,讲明白! Q: 输出下面 console.log 的正确的顺序? const ...
随机推荐
- error 'there is already an open datareader associated with this command which must be closed first'
This can be easily solved by allowing MARS in your connection string. Add MultipleActiveResultSets=t ...
- Redis查询&JDBC查询&Hibernate查询方式的效率比较...
比较三种查询方式查询效率对比...我是用的JavaWeb的方式通过通过JSP页面查询的填写查询的参数...给予反馈.... 整个demo的下载地址:http://files.cnblogs.com/f ...
- 【树】Flatten Binary Tree to Linked List(先序遍历)
题目: Given a binary tree, flatten it to a linked list in-place. For example,Given 1 / \ 2 5 / \ \ 3 4 ...
- 《Mysql技术内幕,Innodb存储引擎》——文件、表
文件 日志 错误日志 对Mysql启动.运行和关闭过程进行记录,通过SHOW VARIABLES LIKE 'log_error'查看日志文件位置. 慢查询日志 Mysql启动时设置一个阈值,运行时间 ...
- 原生JavaScript 导出excel表格(兼容ie和其他主流浏览器)
因同事的需求是想前端导出excel表格,网上找了一些demo,自己修改了一下,可能以后会用到,记录下来吧,兼容ie和一些主流浏览器,ie可能会报错,原因参考 这里,edge 浏览器还没有办法导出,正在 ...
- 常用算法2 - 广度优先搜索 & 深度优先搜索 (python实现)
1. 图 定义:图(Graph)是由顶点的有穷非空集合和顶点之间边的集合组成,通常表示为:G(V,E),其中,G表示一个图,V是图G中顶点的集合,E是图G中边的集合. 简单点的说:图由节点和边组成.一 ...
- Extjs报错处理
错误信息: IE:SCRIPT1009: 缺少 '}' FF: SyntaxError: identifier starts immediately after numeric literal ... ...
- JavaScript部分兼容性函数
1.getElementsByClassName() function getElementsByClassName(node,classname){ if(node.getElementsByCla ...
- MVC初级教程(二)
演示产品源码下载地址:http://www.jinhusns.com/Products/Download
- [日常] 搭建golang开发环境
下载目录:https://studygolang.com/dl32位选 go1.10.linux-386.tar.gz64位选 go1.10.linux-amd64.tar.gz uname -a查看 ...