Skip to content

Instantly share code, notes, and snippets.

@nukisashineko
Last active March 18, 2020 22:02
Show Gist options
  • Save nukisashineko/39c38f4225048ea790f5e9540d1a620d to your computer and use it in GitHub Desktop.
Save nukisashineko/39c38f4225048ea790f5e9540d1a620d to your computer and use it in GitHub Desktop.
nwtgckとの会話の派生でAsyncFunction isなんぞやって確認
// MDN: https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/AsyncFunction
// 参考:https://javascript.developreference.com/article/14715429/ES+2017%3A+async+function+vs+AsyncFunction(object)+vs+async+function+expression
// Q何しようとしたの?
// A友人が話していたAsyncFunctionオブジェクトを触ってみる
// async function が利用するPromiseはグローバルではなくその場でのスコープ変数らしい。
// AsyncFunctionがスコープ変数を参照できなくしているのってPromiseが動的に書き換えられると面倒だからじゃない?って思ったので実験した
// 結果はまあよくわからなかった。
// console.logでの比較式は出力結果と並べてtrueになるようにしている
// 検証はChrome 80.0.3987.132
// グローバル変数を書き換えるので、e.g.間ではタブをリロードして初期化すること
// e.g. 1 グローバルは書き換えない
let NativePromise = Promise;
class CustomPromiseImplementation extends Promise { };
// Promiseだけだと糖衣構文が主でわかりにくかったのでFooも追加してわかりやすく
class AbstructFoo { constructor() { } };
class Foo extends AbstructFoo { constructor() { super(); } };
let NativeFoo = Foo;
class CustomFoo extends AbstructFoo { constructor() { super(); } };
console.log([
Promise.resolve() instanceof Promise === true,
(async () => { })() instanceof Promise === true,
(async () => { })() instanceof NativePromise === true,
(new Foo()) instanceof NativeFoo === true,
(new Foo()) instanceof CustomFoo === false,
]);
// e.g 2 グローバル変数を書き換える (参考のURLにあったやつ)
let NativePromise = Promise;
class CustomPromiseImplementation extends Promise { };
class AbstructFoo { constructor() { } };
class Foo extends AbstructFoo { constructor() { super(); } };
let NativeFoo = Foo;
class CustomFoo extends AbstructFoo { constructor() { super(); } };
// Promise,Fooを書き換え
Promise = CustomPromiseImplementation;
Foo = CustomFoo;
console.log([
Promise.resolve() instanceof Promise === true,
(async () => { })() instanceof Promise === false,
(async () => { })() instanceof NativePromise === true,
(new Foo()) instanceof NativeFoo === false,
(new Foo()) instanceof CustomFoo === true,
]);
// e.g. 3 ローカル変数として書き換える
let NativePromise = Promise;
class CustomPromiseImplementation extends Promise { };
class AbstructFoo { constructor() { } };
class Foo extends AbstructFoo { constructor() { super(); } };
let NativeFoo = Foo;
class CustomFoo extends AbstructFoo { constructor() { super(); } };
let a = 'global';
(function () {
// Promise, Fooをローカル変数として書き換え
let Promise = CustomPromiseImplementation;
let Foo = CustomFoo;
console.log([
Promise.resolve() instanceof Promise === true,
(async () => { })() instanceof Promise === false,
(async () => { })() instanceof NativePromise === true,
(new Foo()) instanceof NativeFoo === false,
(new Foo()) instanceof CustomFoo === true,
]);
})();
// AsyncFunctionでPromise, Fooをローカル変数として書き換え
(function () {
return Object.getPrototypeOf(async function () { }).constructor(`
let Promise = CustomPromiseImplementation;
let Foo = CustomFoo;
let a = 'inner asyncfuncconstructer';
return [
Promise.resolve() instanceof Promise === true,
(async () => {})() instanceof Promise === false,
(async () => {})() instanceof NativePromise === true,
(new Foo()) instanceof NativeFoo === false,
(new Foo()) instanceof CustomFoo === true,
a === 'inner asyncfuncconstructer',
];`)().then(function(resolve){
console.log(resolve);
});
})();
// e.g. 4 スコープ変数として書き換え。通常の無名関数と比べてみたり、AsyncFunctionと比べてみたりする。
let NativePromise = Promise;
class CustomPromiseImplementation extends Promise { };
class AbstructFoo { constructor() { } };
class Foo extends AbstructFoo { constructor() { super(); } };
let NativeFoo = Foo;
class CustomFoo extends AbstructFoo { constructor() { super(); } };
let a = 'global';
// 無名関数内でスコープ変数として書き換え
let normalfunc = (function () {
let Promise = CustomPromiseImplementation;
let Foo = CustomFoo;
let a = 'inner normalfunc';
// e.g. 3 と同じ結果。ちゃんとスコープ変数で束縛されている普通だな。
return function () {
console.log([
Promise.resolve() instanceof Promise === true,
(async () => { })() instanceof Promise === false,
(async () => { })() instanceof NativePromise === true,
(new Foo()) instanceof NativeFoo === false,
(new Foo()) instanceof CustomFoo === true,
a === 'inner normalfunc',
]);
};
})();
// async function内でスコープ変数として書き換え
let asyncfunc = (function () {
let Promise = CustomPromiseImplementation;
let Foo = CustomFoo;
let a = 'inner asyncfunc';
// e.g. 3 と同じ結果。
// ー>ちゃんとスコープ変数で束縛されている?なぜ?スコープ変数で束縛されないはずでは?
return async function () {
return [
Promise.resolve() instanceof Promise === true,
(async () => { })() instanceof Promise === false,
(async () => { })() instanceof NativePromise === true,
(new Foo()) instanceof NativeFoo === false,
(new Foo()) instanceof CustomFoo === true,
a === 'inner asyncfunc',
];
};
})()();
// AsyncFunction constructer内でスコープ変数として書き換え
let asyncfuncconstructer = (function () {
let Promise = CustomPromiseImplementation;
let Foo = CustomFoo;
let a = 'inner asyncfuncconstructer';
// e.g.1 と同じ結果。
// 結果がe.g.1と同じー>スコープ束縛せずにグローバル変数を参照している
return Object.getPrototypeOf(async function () { }).constructor(`
return [
Promise.resolve() instanceof Promise === true,
(async () => {})() instanceof Promise ===true,
(async () => {})() instanceof NativePromise === true,
(new Foo()) instanceof NativeFoo === true,
(new Foo()) instanceof CustomFoo === false,
a === 'global'
];`)
})()();
(function () {
let a = 'inner main';
normalfunc();
asyncfunc.then(function (resolve) {
console.log(resolve);
asyncfuncconstructer.then(function (resolve) {
console.log(resolve);
});
});
})();
// e.g 5 ~async functionとAsyncFunctionは糖衣構文じゃなくて別物だよね(少なくともchromev80の実装では)ってことをe.g.1と同じように確認~
// (追記)async functionとAsyncFunctionは糖衣構文、同じものを指すっぽい、呼び出し方指摘でinstanceofがtrue返すことを確認
let NativePromise = Promise;
class CustomPromiseImplementation extends Promise {};
class AbstructFoo { constructor() {} };
class Foo extends AbstructFoo { constructor() { super(); } };
let NativeFoo = Foo;
class CustomFoo extends AbstructFoo { constructor() { super(); } };
console.log([
Promise.resolve() instanceof Promise === true,
(async () => {})() instanceof Promise === true,
(async () => {})() instanceof NativePromise === true,
(async () => {})() instanceof CustomPromiseImplementation === false,
(async function(){})() instanceof Promise === true,
(async function(){})() instanceof NativePromise === true,
(async function(){})() instanceof CustomPromiseImplementation === false,
(Object.getPrototypeOf(async function () { }).constructor())() instanceof Promise === true,
(Object.getPrototypeOf(async function () { }).constructor())() instanceof NativePromise === true,
(Object.getPrototypeOf(async function () { }).constructor())() instanceof CustomPromiseImplementation === false,
(new Foo()) instanceof NativeFoo === true,
(new Foo()) instanceof CustomFoo === false,
]);
@nwtgck
Copy link

nwtgck commented Mar 18, 2020

激感謝!

e.g 5のObject.getPrototypeOf(async function () { }).constructor()は呼び出しが抜けたよ。ちょっとみづらくなるけど(Object.getPrototypeOf(async function () { }).constructor())()みたいに呼び出しいるかな。他のe.g.だと付いてるのだけど。

@nukisashineko
Copy link
Author

nukisashineko commented Mar 18, 2020

なるほど。理解した。直しとく。ありがと

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment