let fs = require('fs')
fs.readFile('./name.txt','utf-8',(err,data)=>{
console.log(data);
if(data){
fs.readFile(data,'utf-8',(err,data)=>{
console.log(data)
if(data){
fs.readFile(data,'utf-8',(err,data)=>{
console.log(data)
})
}
})
}
})
就这样层层嵌套,人称之为回调地狱,回调函数不好管理,代码阅读性非常差
在使用JavaScript时,为了实现某些逻辑经常会写出层层嵌套的回调函数,如果嵌套过多,会极大影响代码可读性和逻辑,这种情况也被成为回调地狱。
try catch 只能捕获同步异常,不能捕获异步异常
try {
console.log(a)
} catch (error) {
console.log('同步',error)
}
try {
setTimeout(() => {
console.log(a)
}, 30);
} catch (error) {
console.log('异步',error)
}
let fs = require('fs')
/***
* nodejs中很多函数都需要promise化
*/
function readFile(path){
return new Promise((resolve,reject)=>{
fs.readFile(path,'utf-8',(err,data)=>{
if(data){
resolve(data)
}
})
})
}
readFile('./name.txt').then((data)=>{
return readFile(data)
}).then(data=>{
return readFile(data)
}).then(data=>{
console.log(data)
})
promise A+ -> ES6
Promise 构造器主要用于包装不支持promise(返回值不是Promise)的函数。
const promise1 = new Promise((resolve, reject) => {
console.log('promise1', resolve, reject)
});
console.log(2)
// promise1 ƒ () { [native code] } ƒ () { [native code] }
// 2
// 同步执行
我们通过new关键字和Promise构造器创建它的对象。
这个构造器接受一个名为"executor function"的函数。
这个函数应当接受两个函数参数。
当异步任务成功时,第一个函数(resolve)将被调用,并返回一个值代表成功。
当其失败时,第二个函数(reject)将被调用,并返回失败原因(失败原因通常是一个error对象)。
let promise = new Promise(function(resolve,reject){
setTimeout(() => {
Math.random()*100>60?resolve('ok'):reject('no')
}, 30);
})
promise.then(
successVal=>{
console.log(successVal) //ok
},
failValue=>{
console.log(failValue) //no
}
)
let promise = new Promise(function(resolve,reject){
console.log(0)
resolve(1)
})
promise.then(
successVal=>{
console.log(successVal) //ok
},
failValue=>{
console.log(failValue) //no
}
)
console.log(2)
// 0 2 1
let promise = new Promise(function(resolve,reject){
setTimeout(() => {
Math.random()*100>60?resolve('ok'):reject('no')
}, 30);
})
promise.then(
successVal=>{
console.log(successVal) //ok
return 11 //第二次链式调用的值拿到的是第一次return的值
},
failValue=>{
console.log(failValue) //no
return 22
}
).then(
successVal=>{
console.log('then2-',successVal) //ok
},
failValue=>{
console.log('then2-',failValue) //no
}
)
// ok then2- 11
// no then2- 22
let promise = new Promise(function(resolve,reject){
setTimeout(() => {
Math.random()*100>60?resolve('ok'):reject('no')
}, 30);
})
promise.then(
successVal=>{
console.log(successVal) //ok
return new Promise((res,rej)=>{
res('newP2')
})
},
failValue=>{
console.log(failValue) //no
return 22
}
).then(
successVal=>{
console.log('then2-',successVal) //then2- newP2
},
failValue=>{
console.log('then2-',failValue) //no
}
)
let promise = new Promise((res,rej)=>{
res(a)
})
promise.then(
success=>{
console.log(1,success)
},
fail=>{
console.log(2,fail)
// 2 ReferenceError: a is not defined
// 所有的错误都在 reject里捕获
}
)
promise.then(null,(fail)=>{
console.log('reject',fail)
})
promise.catch((fail) =>{
console.log('reject',fail)
})
promise.then(success=>{
console.log('resolve',success)
})..catch((fail) =>{
console.log('reject',fail)
})
let promise = new Promise((res,rej)=>{
res('ok')
console.log(123)//这里仍会执行
console.log(a)//异常,但不会走reject
})
promise.then(
success=>{
console.log(1,success)
//123
//1 'ok'
},
fail=>{
console.log(2,fail)
}
)
let promise = new Promise((res,rej)=>{
console.log(a)
})
promise.then().then().catch((fail) =>{
console.log('reject',fail) //reject ReferenceError: a is not defined
//then()不传递参数的话会直接忽略
})
let p1 = new Promise((res,rej)=>{
setTimeout(() => {
rej(new Error('fail')) //VM189:3 Uncaught (in promise) Error: fail
}, 3000);
})
let p2 = new Promise((res,rej)=>{
setTimeout(() => {
res(p1)
}, 1000);
})
// 异步依赖
读取文件是异步操作,假如有3个读取文件的异步操作,等他们全部执行完后希望拿到汇总的数据
const fs = require('fs')
let promise1 = new Promise((resolve,reject)=>{
fs.readFile('./name.txt','utf-8',function(err,data){
if(err){
reject(err)
}
resolve(data)
})
})
let promise2 = new Promise((resolve,reject)=>{
fs.readFile('./number.txt','utf-8',function(err,data){
if(err){
reject(err)
}
resolve(data)
})
})
const p = Promise.all([promise1,promise2])
p.then(res=>console.log(res))
console.log(p)
MDN
const promise1 = Promise.resolve(3);
const promise2 = 42;
//如果参数中包含非 promise 值,这些值将被忽略,但仍然会被放在返回数组中(如果 promise 完成的话):
const promise3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
});
Promise.all([promise1, promise2, promise3]).then((values) => {
console.log(values);
});
// expected output: Array [3, 42, "foo"]
var p = Promise.all([]); // will be immediately resolved
var p2 = Promise.all([1337, "hi"]); // non-promise values will be ignored, but the evaluation will be done asynchronously
console.log(p);
console.log(p2)
setTimeout(function(){
console.log('the stack is now empty');
console.log(p2);
});
// logs
// Promise { : "fulfilled", : Array[0] }
// Promise { : "pending" }
// the stack is now empty
// Promise { : "fulfilled", : Array[2] }
Promise.all 在任意一个传入的 promise 失败时返回失败。例如,如果你传入的 promise中,有四个 promise 在一定的时间之后调用成功函数,有一个立即调用失败函数,那么 Promise.all 将立即变为失败。
race 函数返回一个 Promise,它将与第一个传递的 promise 相同的完成方式被完成。
它可以是完成( resolves),也可以是失败(rejects),这要取决于第一个完成的方式是两个中的哪个。
如果传的迭代是空的,则返回的 promise 将永远等待。
如果迭代包含一个或多个非承诺值和/或已解决/拒绝的承诺,则 Promise.race 将解析为迭代中找到的第一个值。
race 顾名思义,哪个Promise先跑赢就直接返回
const promise1 = new Promise((resolve, reject) => {
setTimeout(resolve, 500, 'one');
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'two');
});
Promise.race([promise1, promise2]).then((value) => {
console.log(value);
// Both resolve, but promise2 is faster
});
// expected output: "two"
Promise.resolve(value)
let thenable = {
then: (resolve, reject) => {
// resolve(thenable)
resolve(52)
}
}
let p = Promise.resolve(thenable)
p.then(res=>{
console.log(res)//52
})
Promise.resolve("Success").then(function(value) {
console.log(value); // "Success"
}, function(value) {
// 不会被调用
});
var p = Promise.resolve([1,2,3]);
p.then(function(v) {
console.log(v[0]); // 1
});
var original = Promise.resolve(33);
var cast = Promise.resolve(original);
cast.then(function(value) {
console.log('value: ' + value);
});
console.log('original === cast ? ' + (original === cast));
/*
* 打印顺序如下,这里有一个同步异步先后执行的区别
* original === cast ? true
* value: 33
*/
Promise.reject()方法返回一个带有拒绝原因的Promise对象。
Promise.reject(new Error('fail')).then(function() {
// not called
}, function(error) {
console.error(error); // Stacktrace
});
function promisify(func){
return function(...args){
return new Promise((resolve,reject)=>{
func(...args,(err,data)=>{
if(err){
reject(err)
}else{
resolve(data)
}
})
})
}
}
const util = require('util');
console.log(util.promisify)
// [Function: promisify] { custom: Symbol(nodejs.util.promisify.custom) }
console.log(util.pr)
// 1. 异步方法promisify化
let readFileAsync = util.promisify(fs.readFile)
// ……
// 2. 所有fs上的方法都promisify化
function promisifyAll(obj){
for(let [key,fn] of Object.entries(obj)){
if(typeof fn === 'function'){
obj[key+'Async'] = promisify(fn)
}
}
}
promisifyAll(fs);
fs.readFileAsync()
function makeIterator(arr){
var nextIndex = 0;
return {
next(){
if(nextIndex < arr.length){
return {value:arr[nextIndex++],done:false}
}
return {value,undefined,done:true}
}
}
}
var it = makeIterator(['a','b'])
console.log(it,it.next(),it.next())
// 外部迭代器 当你得到一个迭代器并跨越它时,这是一个外部迭代器
for (Iterator iter = var.iterator(); iter.hasNext(); ) {
Object obj = iter.next();
// Operate on obj
}
// 内部迭代器 当你将一个函数对象传递给一个方法来遍历一个列表时,这是一个内部迭代器
var.each( new Functor() {
public void operate(Object arg) {
arg *= 2;
}
});
let obj = {
star:[1,2,3],
end:[7,8,9],
[Symbol.iterator](){
var nextIndex = 0;
var arr = [...this.star,...this.end];
var len = arr.length;
return {
next(){
if(nextIndex<len){
return {value:arr[nextIndex++],done:false}
}else{
return {undefined,done:true}
}
}
}
}
}
// 对象本身不具备迭代器接口,给他加上迭代器接口就可以用of进行遍历
// 为什么对象本身不具备迭代器接口?
// 因为迭代器模式是有序访问聚合对象中的各个元素,而对象本身是无序的
for(let i of obj){
console.log(i);
}
let map = new Map([ ['a',1],['b',2] ])
console.log(map)
// Map(2) {'a' => 1, 'b' => 2}
// [[Entries]]
// 0: {"a" => 1}
// 1: {"b" => 2}
for(let m of map){
console.log(m)
// (2) ['a', 1]
// (2) ['b', 2]
}
for(let [k,v] of map){
console.log(k,v)
}
let obj = {
a:1,
b:2,
c:3,
// [[a,1],[b,2],[c,3]]
[Symbol.iterator](){
let nextIndex = 0
let map = new Map();
for(let [k,v] of Object.entries(this)){
console.log(k,v)
map.set(k,v)
}
console.log(map);
let mapEntries = [...map.entries()];
console.log(mapEntries);
return {
next(){
return nextIndex<map.entries.length ?
{value: mapEntries[nextIndex++],done:false}:
{value: undefined,done:true}
},
return(){
// 遍历中break,报错等终止for循环后 走这儿
console.log(1,'return')
return {value:1,done:false}
}
}
}
}
for(let i of obj){
console.log(i)
// break
throw new Error('hello')
}
iterator默认调用迭代器接口的场合
function 和 函数名 中间具有分号时,为生成器函数,他返回一个迭代器对象
function * test(){}
function* test(){}
function *test(){}
生成器函数的返回值是迭代器
yield可以产出相同的值
function * test2(){
let b = [1,2]
yield b;
yield b;
}
let it = test2()
let next1 = it.next().value;
let next2 = it.next().value
console.log(next1)
console.log(next2)
console.log(next1===next2)
yield有记忆功能,可以暂停函数,return是函数终止
生成器里面不能有break
yield 只能出现在生成器函数中
function * test(){
yield 'a';
console.log(1);
yield 'b';
return 'c';
}
let it = test()
console.log(it.next())
console.log(it.next())
console.log(it.next())
console.log(it.next())
// {value: 'a', done: false} 如果产出的值为yield,done为false
// 1
// {value: 'b', done: false}
// {value: 'c', done: true} 如果产出的值为return,done为true
// {value: undefined, done: true}
yield的返回值是由next决定的
function * test2(){
let a = yield 'a';
console.log(a);//undefined
yield 'b';
return 'c';
}
let it = test2()
console.log(it.next())
console.log(it.next())
// =============
function * test2(){
let a = yield 'a';
console.log(a);//10
yield 'b';
return 'c';
}
let it = test2()
console.log(it.next())
console.log(it.next(10))
// yield并不产出值,他的参数由next决定
//=======================
function * foo(){
let value1 = yield 1;
console.log('value1:',value1);
let value2 = yield 2;
console.log('value2:',value2);
let value3 = yield 3;
console.log('value3:',value3);
}
let it = foo();
console.log(it.next())
console.log(it.next('two'))
console.log(it.next('three'))
console.log(it.next('four'))
yield 是一个单独的表达式,作为子表达式时需要加括号
function * demo(){
console.log('demo123')
}
let it = demo()
console.log(it.next())
function * demo2(){
// yield 是一个单独的表达式,作为子表达式时需要加括号
console.log('hello',(yield 123))
}
let it = demo2()
console.log(it.next()) // {value: 123, done: false}
console.log(it.next()) //hello {value: undefined, done: true}
生成器中只遍历yield,不会遍历return的值
function * foo(){
yield 1;
yield 2
return 3;
}
for(let i of foo()){
console.log('test',i)
}
// test 1
// test 2
// 遍历的时候不会遍历return的值
使用生成器配置迭代器接口
let obj = {
star:[1,2,3],
end:[7,8,9],
// [Symbol.iterator](){
[Symbol.iterator]: function* (){
var nextIndex = 0;
var arr = [...this.star,...this.end];
var len = arr.length;
// return {
// next(){
// if(nextIndex
// return {value:arr[nextIndex++],done:false}
// }else{
// return {undefined,done:true}
// }
// }
// }
while(nextIndex < len){
yield arr[nextIndex++]
}
}
}
// 对象本身不具备迭代器接口,给他加上迭代器接口就可以用of进行遍历
// 为什么对象本身不具备迭代器接口?
// 因为迭代器模式是有序访问聚合对象中的各个元素,而对象本身是无序的
for(let i of obj){
console.log(i);
}
const fs = require('fs');
const util = require('util')
const readFile = util.promisify(fs.readFile);
function * read(){
let value1 = yield readFile('./name.txt','utf-8');
let value2 = yield readFile(value1,'utf-8');
let value3 = yield readFile(value2,'utf-8');
console.log(value3)
}
let iter = read();
// 1. =====================
// let {value,done} = iter.next();
// value.then((res1)=>{
// // console.log(res1)
// // iter.next(res1)
// let {value,done} = iter.next(res1);
// value.then(res2=>{
// let {value,done} = iter.next(res2);
// value.then(res3=>{
// console.log(res)
// })
// })
// })
// 2. =======优化=========
function Co(iter){
return new Promise((resolve,reject)=>{
let next = (data)=>{
let {value,done} =iter.next(data);
if(done){
res(value)
}else{
value.then((res)=>{
next(res)
})
}
}
next()
})
}
let p = Co(read)
p.then((res)=>{
console.log(res)
})
// 3.====================
// Co也是npm中的一个同名包
// TJ koa co express jade mocha
// let co = require('co')
// let p = co(read)
// p.then((res)=>{
// console.log(res)
// })
// Co也是async的由来
async function read(){
let value1 = await readFile('./name.txt','utf-8');
let value2 = await readFile(value1,'utf-8');
let value3 = await readFile(value2,'utf-8');
console.log(value3)
}
function * get(){
yield 1;
// 2. r
// return 10
yield 2;
yield 3;
}
let g = get();
console.log(g.next())
// 迭代器的return方法相当于生成器中显示调用return方法
// return 可以产出值,也会终止函数,done->true 已经完成
// return 后面next的value->undefined
// 1. r
console.log(g.return(10))
console.log(g.next())
console.log(g.next())
console.log(g.next())
try catch 只能捕获同步异常,不能捕获异步异常
function * get(){
yield 1;
try {
yield 2;
} catch (error) {
console.log('生成器内部异常',error)
}
yield 3;
console.log('end')
}
let g = get()
// 1.
// console.log(g.throw('a')) //VM166:1 Uncaught a 此时为全局异常 抛出错误,生成器无法捕获
// 2.
console.log(g.next())
console.log(g.next())
// ----------------
console.log(g.throw('a'))
// 抛出异常,生成器内部异常 a
// {value: 3, done: false}
// throw = 抛出错误 + next 两层左右
// ----------------
console.log(g.throw('b')) ///VM166:1 Uncaught a ->全局异常
console.log(g.next())
console.log(g.next())
// 生成器函数中可以直接捕获异步代码的异常
let fs = require('fs')
let util = require('util')
let co = require('co')
let readFile = util.promisify(fs.readFile)
function * read(){
// yield fs.readFile()
// yield异步代码 必须用promise包裹
try {
let value1 = yield readFile('./name.txt','utf-8')
let value2 = yield readFile(value1,'utf-8')
let value3 = yield readFile(value2,'utf-8')
} catch (error) {
console.log('异步',error)
}
console.log('hello end')
}
let p = co(read());
p.then(res=>{
console.log(res)
})
let fs = require('fs')
let util = require('util')
let co = require('co')
let readFile = util.promisify(fs.readFile)
async function read() {
let value1 = await readFile('./name.txt', 'utf-8')
let value2 = await readFile(value1, 'utf-8')
let value3 = await readFile(value2, 'utf-8')
console.log('hello end')
}
// let p = co(read());
let p = read();
p.then(res => {
console.log(res)
})
async function test(){
// var value = '1';
var value = await '1';
// console.log(a)
// console.log('after err') //出错后会终止程序执行
console.log(value) //1
// 可以用try catch 捕获
try {
console.log(a)
} catch (error) {
console.log('try',error)
}
console.log('after err')
return value;
}
let t = test()
console.log(t) //Promise {: '1'}
t.then(res=>{
console.log('then',res) //then 1
},rej=>{
console.log('err',rej) // err ReferenceError: a is not defined
})
var arr = [1,2,3,4,5]
for (const item of arr) {
console.log(item)
}
// generator 生成器->迭代器 iterator
function * test(arr){
for (const item of arr) {
yield item
}
}
let iter = test(arr)
console.log(iter.next())
var functions = [
function test1(next) {
console.log('test1')
next()
},
function test2(next) {
console.log('test2')
next()
// next() 没有next 就会到此阶段
}
,
function test3(next) {
console.log('test3')
next()
}
]
; (function () {
function* generator(arr) {
for (let index = 0; index < arr.length; index++) {
yield arr[index];
}
}
const iterator = generator(functions);
const init = () => {
nextDo(iterator.next())
}
function nextDo(n) {
// n.value 传递进来的函数集合参数
n.value(
function () {
const n = iterator.next();
if (!n.done) {
nextDo(n)
} else {
return;
}
}
)
}
init()
})()