关于javascript:一道打印顺序引发的血案

10次阅读

共计 3166 个字符,预计需要花费 8 分钟才能阅读完成。

一道打印程序引发的血案

异步编程是 JS 中重要的模块,前几日逛 B 站,刷到这么一个发问,拿来钻研一下:

let promise1 = Promise.resolve()
    .then(res => console.log(1))
    .then(res => console.log(2))

let promise2 = new Promise(resolve => {setTimeout(() => {console.log(6)
        resolve()})
}).then(res => console.log(3))

async function main() {console.log(4)
    console.log(await Promise.all([promise2, promise1]))
    console.log(5)
    return {obj: 5}
}

let promise3 = Promise.resolve()
    .then(res => console.log(8))
    .then(res => console.log(9))

console.log(typeof main())
变量对象申明

首先会创立变量对象,申明函数和变量,函数的申明优先级比变量高。会变成

VO = {main: reference async function(){},
  promise1: undefined,
  promise2: undefined,
  promise3: undefined,
}

接下来 代码执行阶段,首先会对变量进行赋值:

对 promise1 来说:
Promise.resolve() 会立刻执行
then(res => console.log(1)).then... 会放入本轮的微工作

对 promise2 来说
开启一个 setTimeout 宏工作,之后的 then 会在宏工作完结后的 当次 微工作 中执行

对 promise3 来说:
Promise.resolve() 会立刻执行
then(res => console.log(8)).then... 会放入本轮的微工作

进入 main 函数:
执行 console.log(4) 
执行 console.log(await Promise.all([promise2, promise1])) 
这一步是整个函数最要害的中央。

async…await 执行程序

async…await 是 generator 的语法糖。实质是 generator + co 库,内置函数执行器。会主动执行每一个 yeild,把最初执行的后果通过 Promise resolve 的形式抛出。不便链式调用。
咱们把代码通过 babel 转译,能够看上面代码中正文的 1、2 两个中央。

"use strict";

function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { 
  try {var info = gen[key](arg); 
    var value = info.value; 
  } catch (error) {reject(error); return; 
  } 
  if (info.done) {resolve(value); 
  } else {Promise.resolve(value).then(_next, _throw); 
  } 
}

function _asyncToGenerator(fn) {return function () { 
    var self = this, 
    args = arguments; 
    // 2. 执行 async 首先返回一个 promise
    // 返回之前会先执行完 Promise 外面的 executor 函数
    return new Promise(function (resolve, reject) {var gen = fn.apply(self, args); 
      function _next(value) {asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); 
      } 
      function _throw(err) {asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } 
        _next(undefined); 
    });
  }; 
}

var promise1 = Promise.resolve().then(function (res) {return console.log(1);
}).then(function (res) {return console.log(2);
});
var promise2 = new Promise(function (resolve) {setTimeout(function () {console.log(6);
    resolve();});
}).then(function (res) {return console.log(3);
});

function main() {return _main.apply(this, arguments);
}

function _main() {
  // 1. main 函数开始真正执行的是 _asyncToGenerator
  _main = _asyncToGenerator(/*#__PURE__*/regeneratorRuntime.mark(function _callee() {
    // 3. regeneratorRuntime 函数来自 facebook 的 regenerator 模块,用来编译 generator 函数
    // mark 函数为 指标函数的原型链上注入了 next、throw、return 等函数
    // wrap 函数包装一层,把 next 的调用指向内部的 context
    // 这一步外围能够看 regenerator 源码
    return regeneratorRuntime.wrap(function _callee$(_context) {while (1) {switch (_context.prev = _context.next) {
          case 0:
            console.log(4);
            _context.t0 = console;
            _context.next = 4;
            return Promise.all([promise2, promise1]);

          case 4:
            _context.t1 = _context.sent;

            _context.t0.log.call(_context.t0, _context.t1);

            console.log(5);
            return _context.abrupt("return", {obj: 5});

          case 8:
          case "end":
            return _context.stop();}
      }
    }, _callee);
  }));
  return _main.apply(this, arguments);
}

var promise3 = Promise.resolve().then(function (res) {return console.log(8);
}).then(function (res) {return console.log(9);
});
console.log(typeof(main()));

期待 console.log(await Promise.all([promise2, promise1])) 执行完,这一行比拟有迷惑性,promise1 和 promise2 的执行后面曾经触发,此处只是等他们的异步全副执行完。
之后的执行就是同步操作了

自此残缺输入程序为:

 4
'object' //async 函数返回
 1
 8
 2
 9
 6
 3
[undefined, undefined]
 5
regenerator

对于 regenerator 模块的参考资料,感兴趣的能够理解以下材料

1、https://www.iteye.com/blog/schifred-2369320
2、https://juejin.cn/post/6844903701908291592

正文完
 0