2016-09-08 2 views
1

다음 코드는 몇 가지 숫자를 저장하겠다는 약속의 배열을 작성한 다음 co 라이브러리를 사용하여 약속을 생성하고 결과를 인쇄합니다. 그러나 내가 이해하지 못하는 것은 출력을 출력 할 때 동일한 레코드를 10 번 인쇄한다는 것입니다. I는 약속 내부 변수 x를 선언하면, 그때 예상 결과 (예를 들어 10 개의 얻을mongoose와 es6이 예상대로 작동하지 않는다고 약속합니다.

/tmp/test$ node m 
{"__v":0,"num":9,"_id":"57d1931037a370055f51977c"} 
{"__v":0,"num":9,"_id":"57d1931037a370055f51977c"} 
{"__v":0,"num":9,"_id":"57d1931037a370055f51977c"} 
{"__v":0,"num":9,"_id":"57d1931037a370055f51977c"} 
{"__v":0,"num":9,"_id":"57d1931037a370055f51977c"} 
{"__v":0,"num":9,"_id":"57d1931037a370055f51977c"} 
{"__v":0,"num":9,"_id":"57d1931037a370055f51977c"} 
{"__v":0,"num":9,"_id":"57d1931037a370055f51977c"} 
{"__v":0,"num":9,"_id":"57d1931037a370055f51977c"} 
{"__v":0,"num":9,"_id":"57d1931037a370055f51977c"} 

주 : 여기

'use strict' 
const Promise = require('bluebird'); 
const co = require('co'); 
const _ = require('lodash'); 
const mongoose = require('mongoose'); 

// plug in the bluebird promise library for mongoose 
mongoose.Promise = Promise; 

mongoose.connect('mongodb://localhost:27017/nodejs_testing'); 

const numSchema = new mongoose.Schema({ 
    num: { type: Number, required: true } 
}); 
const Num = mongoose.model('Num', numSchema); 

let promises = []; 
let x; 

// create an array of promises to save some numbers 
for (let i = 0; i < 10; ++i) { 
    let p = new Promise((resolve,reject) => { 
    x = Num(); 
    x.num = i; 
    x.save((err) => { 
     if (err) { 
     reject(err); 
     } else { 
     resolve(x); 
     } 
    }); 
    }); 
    promises.push(p); 
}; 

// yield all the promises, then print out the results 
co(function *() { 
    let res = yield Promise.all(promises); 
    _.each(res, item => { 
    console.log(JSON.stringify(item)); 
    }); 
    mongoose.disconnect(); 
}); 

가 출력된다 : 여기

는 코드 출력의 숫자). 즉,이 변경 (아래 참조)을하면 예상대로 작동합니다.

let p = new Promise((resolve,reject) => { 
    let x = Num(); // <--- declare x inside the promise 
    . 
    . 
    }); 

제 질문은이 코드가이 방식으로 작동하는 이유는 무엇입니까? mongodb/mongoose를 사용하여 정확히 동일한 유형의 테스트를 반복하고 일부 번호 만 인쇄하면 Promise 외부에서 x으로 선언 된 경우에도 예상대로 작동합니다. 아래의 샘플 코드 :

'use strict' 
const Promise = require('bluebird'); 
const co = require('co'); 
const _ = require('lodash'); 

class Number { 
    constructor(num) { 
    this.num = num; 
    } 
}; 

let x; 
let promises = []; 

for (let i = 0; i < 10; ++i) { 
    let p = new Promise((resolve,reject) => { 
    setTimeout(() => { 
     x = new Number(i); 
     resolve(x); 
    }, 300); 
    }); 
    promises.push(p); 
}; 

co(function *() { 
    let res = yield Promise.all(promises); 
    _.each(res, item => { 
    console.log(JSON.stringify(item)); 
    }); 
}); 

출력 :

/tmp/test$ node t 
{"num":0} 
{"num":1} 
{"num":2} 
{"num":3} 
{"num":4} 
{"num":5} 
{"num":6} 
{"num":7} 
{"num":8} 
{"num":9} 

답변

2

이 차이는 대 비 몽구스를 몽구스되지 않습니다. 코드가 다른 일을하고 있습니다. 첫 번째 예에서

, 당신은 (*** 의견을 참조) 한 :

x 해당 코드에있는 루프 밖에서 선언
let p = new Promise((resolve,reject) => { 
    x = Num();    // *** A 
    x.num = i; 
    x.save((err) => { 
    if (err) { 
     reject(err); 
    } else { 
     resolve(x);   // *** B 
    } 
    }); 
}); 

..., 그래서 모든 반복 변수를 다시 사용합니다.

위의 A와 B로 표시된 문은 서로 비동기 적으로이됩니다. B이 발생하면 모두가 번 반복되었습니다. A; B의 마지막 값이 x에 할당 된 것으로 보았습니다. 그게 바로 해결을 위해 사용 된 것이고 모두 같은 값으로 처리됩니다. 두 번째 예와 비교

:

let p = new Promise((resolve,reject) => { 
    setTimeout(() => { 
    x = new Number(i);  // *** A 
    resolve(x);   // *** B 
    }, 300); 
}); 

두 사람은 이제 서로 동 기적으로 일어나고 있습니다; B은 해상도를 변경할 때마다 당시의 현재 값 x을 사용합니다.

그 이유는 둘 사이의 동작이 다릅니다. 항상 당신이 할 수있는 가장 좁은 범위에 선언

//let x;       // *** Not here 

// create an array of promises to save some numbers 
for (let i = 0; i < 10; ++i) { 
    let p = new Promise((resolve,reject) => { 
    let x = Num();    // *** Here 
    x.num = i; 
    x.save((err) => { 
     if (err) { 
     reject(err); 
     } else { 
     resolve(x); 
     } 
    }); 
    }); 
} 

이되는 규칙을 기억

기본적으로 x약속 초기화 콜백 내 가까이가 사용되는 곳이 많이 선언해야한다.

+1

(내가 언급 한 질문에) 그러나 나는 단지 내가 왜 그런 행동을하는지 이해하고 싶었다. 어쨌든, 좋은 설명, 고마워! – dcp

2

x이 for 루프의 범위를 벗어 났기 때문에이 문제가 발생합니다. for 루프를 실행하면 x의 다른 변수를 인스턴스화하는 것이 아니라 원래 x 값을 재 할당합니다. 무엇 일어나는 것은 최종 값 x가 다른 값 전에 Num 값 (9)가 몽고에 저장하고 x가 9

로 설정하기 전에 당신이 원하는 경우 배열에 다른 약속이 해결되지 않는 경우입니다 취한다는 것입니다 적절한 출력이 단지 내부 x을 PLAE해야하는 루프 : 네, 약속의 내부와 그 문제를 해결할 이렇게 변수 x를 선언하는 것이 더 알고 있었다

// create an array of promises to save some numbers 
for (let i = 0; i < 10; ++i) { 
    let x; 
    let p = new Promise((resolve,reject) => { 
    x = Num(); 
    x.num = i; 
    x.save((err) => { 
     if (err) { 
     reject(err); 
     } else { 
     resolve(x); 
     } 
    }); 
    }); 
    promises.push(p); 
}; 
+0

@ T.J.Crowder point taken. 감사! – Mike

+1

@ T.J.Crowder 했어요. – Mike