promise异步

  1. js是单线程的
  2. js异步的核心就是事件循环

回调地狱

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)
    }
    

解决回调地狱

Promise对象

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)
})

Generator函数

async函数

promise

promise A+ -> ES6

Promise 构造器

Promise 构造器主要用于包装不支持promise(返回值不是Promise)的函数。

  • new Promise(executor)
    • executor
      这是一个双参函数,参数为resolve和reject。
      Promise的实现会立即执行executor,并传入resolve和reject函数
      (Promise构造器将会在返回新对象之前executor)。
      当resolve和reject函数被调用时,它们分别对promise执行resolve和reject。
      executor通常会触发一些异步运算,一旦运算成功完成,则resolve掉这个promise,如果出错则reject掉。
      如果executor函数执行时抛出异常,promise状态会变为rejected。executor的返回值也会被忽略。
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对象)。

Promise状态-待定|已兑现|已拒绝

  • 一个 Promise 必然处于以下几种状态之一:
    1. 待定(pending): 初始状态,既没有被兑现,也没有被拒绝。
    2. 已兑现(fulfilled): 意味着操作成功完成。
    3. 已拒绝(rejected): 意味着操作失败。
    • 待定状态的 Promise 对象要么会通过一个值被兑现(fulfilled),要么会通过一个原因(错误)被拒绝(rejected)。
    • 当这些情况之一发生时,我们用 promise 的 then 方法排列起来的相关处理程序就会被调用。如果 promise 在一个相应的处理程序被绑定时就已经被兑现或被拒绝了,那么这个处理程序就会被调用,因此在完成异步操作和绑定处理方法之间不会存在竞争状态。

基本用法

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

链式调用和返回值

  1. 直接return值
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
  1. return一个Promise
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里捕获
    }
)
  • catch捕获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);
})
// 异步依赖

  • resolve、reject不会终止函数运行

Promise.all()

方法介绍

  • 方法接收一个promise的iterable类型(注:Array,Map,Set都属于ES6的iterable类型)的输入,
  • 并且只返回一个Promise实例,
  • 那个输入的所有promise的resolve回调的结果是一个数组。
  • 这个Promise的resolve回调执行是在所有输入的promise的resolve回调都结束,或者输入的iterable里没有promise了的时候。
  • 它的reject回调执行是,只要任何一个输入的promise的reject回调执行或者输入不合法的promise就会立即抛出错误,并且reject的是第一个抛出的错误信息。

使用

读取文件是异步操作,假如有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"]

同步

  • 但是,Promise.all 当且仅当传入的可迭代对象为空时为同步:
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 { <state>: "fulfilled", <value>: Array[0] }
// Promise { <state>: "pending" }
// the stack is now empty
// Promise { <state>: "fulfilled", <value>: Array[2] }

Promise.all 的快速返回失败行为

Promise.all 在任意一个传入的 promise 失败时返回失败。例如,如果你传入的 promise中,有四个 promise 在一定的时间之后调用成功函数,有一个立即调用失败函数,那么 Promise.all 将立即变为失败。

Promise.race()

  • 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()

Promise.resolve(value)

  • value 将被Promise对象解析的参数,也可以是一个Promise对象,或者是一个thenable。
  • 返回值 返回一个带着给定值解析过的Promise对象,如果参数本身就是一个Promise对象,则直接返回这个Promise对象。
  • 如果这个值是thenable(即带有"then" 方法),返回的promise会“跟随”这个thenable的对象,采用它的最终状态;否则返回的promise将以此值完成。此函数将类promise对象的多层嵌套展平。
let thenable = {
    
    
    then: (resolve, reject) => {
    
    
        // resolve(thenable)
        resolve(52)
    }
}
let p = Promise.resolve(thenable)
p.then(res=>{
    
    
    console.log(res)//52
})
  • 使用静态Promise.resolve方法
Promise.resolve("Success").then(function(value) {
    
    
  console.log(value); // "Success"
}, function(value) {
    
    
  // 不会被调用
});
  • resolve一个数组
var p = Promise.resolve([1,2,3]);
p.then(function(v) {
    
    
  console.log(v[0]); // 1
});
  • resolve另一个promise
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.reject()方法返回一个带有拒绝原因的Promise对象。

Promise.reject(new Error('fail')).then(function() {
    
    
  // not called
}, function(error) {
    
    
  console.error(error); // Stacktrace
});
  • Promise.reject()不能使用thenable

自定义promisify

  • 和readFile()函数一样,nodejs中很多函数都需要promise化来解决地狱回调的问题
  • fs.readFile(data,‘utf-8’,(err,data)=>{})此类函数的promisify化
function promisify(func){
    
    
    return function(...args){
    
    
        return new Promise((resolve,reject)=>{
    
    
            func(...args,(err,data)=>{
    
    
                if(err){
    
    
                    reject(err)
                }else{
    
    
                    resolve(data)
                }
            })
        })
    }
}
  • node中的promisify工具方法
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;
  }
});

对象配置迭代器接口

  • array map set string TypeArray NodeList arguments 这些都实现了迭代器接口,只有object没有
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);
}
  • map
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)
}
  • map迭代器
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默认调用迭代器接口的场合

  1. …扩展运算符
  2. for of
  3. Array.from()

生成器函数

函数声明

function 和 函数名 中间具有分号时,为生成器函数,他返回一个迭代器对象

function * test(){
    
    }
function* test(){
    
    }
function  *test(){
    
    }

yield 关键字

  • 生成器函数的返回值是迭代器

  • 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<len){
    
    
        //             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)
}

生成器返回的迭代器中的方法

next

return

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())

throw

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)
})

async

  1. 内置的执行器co
  2. 更好的语义
  3. 更广的实用性
  4. 返回值一定是promise
  5. 无论如何显示地返回,最后的返回值会再次被promise包装
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 {<fulfilled>: '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()
})()

猜你喜欢

转载自blog.csdn.net/uotail/article/details/124718892